[HNOI2015]菜肴制作
时间限制: 1 Sec 内存限制: 512 MB题目描述
知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴。
输入
第一行是一个正整数D,表示数据组数。
输出
输出文件仅包含 D 行,每行 N 个整数,表示最优的菜肴制作顺序,或
样例输入
3
5 4
5 4
5 3
4 2
3 2
3 3
1 2
2 3
3 1
5 2
5 2
4 3
样例输出
1 5 3 4 2
Impossible!
1 5 2 4 3
提示
【样例解释】
1
6 6
6 5
6 4
4 3
3 1
2 1
5 2
正解是6 5 2 4 3 1,如果我没猜错你的答案是6 4 3 5 2 1,但是2是能靠前就靠前的,因此这种做法是错误的。 常规做法有一个很大的弊端,就是他忽略了他向下找入度为0的点的途中所遇到的点,这就很尴尬了,那我们应该怎么搞呢?
正解是倒着搞一遍,把边和入度全部打过来,贪心找最大的,最后答案也要倒着输出,不难发现这样一下子就A了,然而具体原因我和Q某犇在一起捣鼓了半天才貌似给出了证明,如有不对请指正。
首先,我们之所以不去正着贪心是因为这样会忽略一个比当前点更小的点得存在,也就不得不将它本来应当存在的位置靠后,而倒着找就会忽略比当前点都大的点的位置,然而如果我们直接去找最大的位置的话那么必须经过的那个更小的点的实际访问顺序就会越靠后,然而实际并不是这样,越小的是越尽量靠前的,因此如果这样做反而是错的了,但对于正着搜就不然,然而我们貌似不好或者无法实现……
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<algorithm> 6 #include<map> 7 #include<queue> 8 #include<string> 9 #include<cmath> 10 using namespace std; 11 int t,n,m,zz,zz2,rd[100005]; 12 int a[100005],b[100005],jg[100005]; 13 struct ro{ 14 int to; 15 int next; 16 }road[100005],road2[100005]; 17 void build(int x,int y){ 18 zz++; 19 road[zz].to=y; 20 road[zz].next=a[x]; 21 a[x]=zz; 22 } 23 priority_queue<int> q1; 24 int main(){ 25 scanf("%d",&t); 26 while(t--) 27 { 28 memset(rd,0,sizeof(rd)); 29 memset(a,0,sizeof(a)); 30 zz=0; 31 zz2=0; 32 memset(b,0,sizeof(b)); 33 scanf("%d%d",&n,&m); 34 for(int i=1;i<=m;i++) 35 { 36 int x,y; 37 scanf("%d%d",&x,&y); 38 build(y,x); 39 rd[x]++; 40 } 41 for(int i=1;i<=n;i++) 42 { 43 if(!rd[i]) 44 q1.push(i); 45 } 46 while(!q1.empty()) 47 { 48 int x=q1.top(); 49 q1.pop(); 50 zz2++; 51 jg[zz2]=x; 52 for(int i=a[x];i>0;i=road[i].next) 53 { 54 int y=road[i].to; 55 rd[y]--; 56 if(!rd[y]) 57 q1.push(y); 58 } 59 } 60 if(zz2==n) 61 { 62 for(int i=zz2;i>0;i--) 63 printf("%d ",jg[i]); 64 printf("\n"); 65 } 66 else 67 { 68 printf("Impossible!\n"); 69 } 70 } 71 //while(1); 72 return 0; 73 }
附上同时和我一起做这道题的Q某犇的题解(貌似他的证明和我不太一样)传送门->http://blog.csdn.net/qty2001/article/details/77103300