Problem 1041 - 女儿岛游记
题目描述:
Description
话说,一日,Qinz大牛游荡到了一个岛上,惊喜地发现这岛就是传说中的“女儿岛”,岛上美女如云,Qinz每日与众美女游山玩水,不亦乐乎。直到有一天,Qinz发现自己的胡子不但不长了反而往下掉,而且体型也发生了变化……Qinz要变成女人了!悲痛之时,女儿岛的岛主—女帝给了Qinz一些药水和一本宝典,并告诉“她”,只要按宝典规定的顺序服下药水就能恢复男儿身。宝典上规定了某些药必须在服用了另一些药的前提下才可服用,不然将产生可怕的反作用(比如变成双性人)。不幸的是,由于年代久远,宝典上的一些字已经模糊不清了,然而服药的顺序只可能有一种。请问Qinz能够根据已知的关系找出这唯一的服药顺序,从而顺利地变回纯爷们吗?(提示:宝典上的条目可能会重复,药水的关系不会形成环)
Input
输入的第一行包含一个整数T,表示有T组数据。
每组数据的第一行包含两个整数N(2≤N≤50),M(0≤M≤60)。分别表示药水的数量和宝典上能够看清的条目数。
接下来的M行,每行两个整数 A B。表示必须服用药水编号为A的药水后才能服用编号为B的药水,药水编号从1到N。
Output
每组数据输出一行,如果Qinz能够确定这唯一的服用顺序,输出该顺序,否则输出-1。
Sample Input
3
2 1
1 2
3 3
3 1
2 1
2 3
4 2
1 2
3 4
Sample Output
1 2
2 3 1
-1
分析过程:
这个题我用了两种方法,第一种方法:建表,采用了类似Pro1037智破机枪阵的方法,用匈牙利算法求出结果,如果最终生成的最大链长度不是N,就输出-1。
代码:
第二种方法:
见一个数组,list[i]表示i元素应该在第几个出现。不停的刷list的数据,直到不再变化为止。算法复杂度应该是O(N3)吧,但是因为数据量小,所以能过。
如果药典给的提示不够的话,那么list中必然有两个或以上的相同元素,此时也必缺少某个位置应该出现的元素,输出-1
代码:
题目描述:
Description
话说,一日,Qinz大牛游荡到了一个岛上,惊喜地发现这岛就是传说中的“女儿岛”,岛上美女如云,Qinz每日与众美女游山玩水,不亦乐乎。直到有一天,Qinz发现自己的胡子不但不长了反而往下掉,而且体型也发生了变化……Qinz要变成女人了!悲痛之时,女儿岛的岛主—女帝给了Qinz一些药水和一本宝典,并告诉“她”,只要按宝典规定的顺序服下药水就能恢复男儿身。宝典上规定了某些药必须在服用了另一些药的前提下才可服用,不然将产生可怕的反作用(比如变成双性人)。不幸的是,由于年代久远,宝典上的一些字已经模糊不清了,然而服药的顺序只可能有一种。请问Qinz能够根据已知的关系找出这唯一的服药顺序,从而顺利地变回纯爷们吗?(提示:宝典上的条目可能会重复,药水的关系不会形成环)
Input
输入的第一行包含一个整数T,表示有T组数据。
每组数据的第一行包含两个整数N(2≤N≤50),M(0≤M≤60)。分别表示药水的数量和宝典上能够看清的条目数。
接下来的M行,每行两个整数 A B。表示必须服用药水编号为A的药水后才能服用编号为B的药水,药水编号从1到N。
Output
每组数据输出一行,如果Qinz能够确定这唯一的服用顺序,输出该顺序,否则输出-1。
Sample Input
3
2 1
1 2
3 3
3 1
2 1
2 3
4 2
1 2
3 4
Sample Output
1 2
2 3 1
-1
分析过程:
这个题我用了两种方法,第一种方法:建表,采用了类似Pro1037智破机枪阵的方法,用匈牙利算法求出结果,如果最终生成的最大链长度不是N,就输出-1。
代码:
程序代码:
#include <stdio.h> #include <string.h> int N,M; unsigned char map[64][64]; unsigned char exist[64],after[64]; int find(int x) { int i; for(i=1;i<=N;i++) { if( map[i][x] && !exist[i]) { exist[i]=1; if(after[i]==0 || find(after[i])) { after[i]=x; return 1; } } } return 0; } int main(int argc, char *argv[]) { int T;scanf("%d",&T); while(T--) { int a,b,i,firstOne=0; memset(map,0,sizeof(map)); memset(after,0,sizeof(after)); scanf("%d%d",&N,&M); for(i=0;i<M;i++) { scanf("%d%d",&a,&b); map[a][b]=1; } for(i=1;i<=N;i++) { memset(exist,0,sizeof(exist)); if(!find(i)) { if(firstOne==0) firstOne=i; else { printf("-1"); break; } } } if(i>N){ int x=firstOne; for(i=1;i<=N;i++) printf("%d ",x),x = after[x]; } printf("\n"); } return 0; }
第二种方法:
见一个数组,list[i]表示i元素应该在第几个出现。不停的刷list的数据,直到不再变化为止。算法复杂度应该是O(N3)吧,但是因为数据量小,所以能过。
如果药典给的提示不够的话,那么list中必然有两个或以上的相同元素,此时也必缺少某个位置应该出现的元素,输出-1
代码:
程序代码:
#include <iostream> #include <string.h> int N,M; int d[64][2]; int list[64]; int ansLst[64]; using namespace std; bool cal() { bool ans=true; for(int i=0;i<M;i++) { if(list[d[i][0]]>=list[d[i][1]]) { list[d[i][1]]=list[d[i][0]]+1; ans = false; } } return ans; } bool mkAns() { for(int i=0;i<N;i++) { int j=1; for(j=1;j<=N;j++) { if(list[j] == i) { ansLst[i]=j; break; } } if(j>N) return false; } return true; } int main(int argc, char *argv[]) { int T;cin>>T; while(T--) { memset(d,0,sizeof(d)); memset(ansLst,0,sizeof(ansLst)); memset(list,0,sizeof(list)); cin>>N>>M; for (int i=0; i<M; i++) { cin>>d[i][0]>>d[i][1]; } while(!cal()); if(mkAns()){ for (int i=0; i<N; i++) cout<<ansLst[i]<<' '; cout<<endl; }else cout<<"-1"<<endl; } }