题意:有n个球,他的重量从1到n个重量单位,每一个球都有自己的重量单位,并不会重复,现在给你一些顺序a b,表示a的重量比b小,让你按字典序最小找出符合所有条件的序列每一个元素表示i-th个球在序列中的位置。
想法:开始以为直接正向建边然后,top_sort从小到大找,然后输出就好了。但是这样是不对的,因为我们可以知道,如果用这种方法,得到的是球的编号的字典序输出。
5 4
5 1
4 2
1 3
2 3
就是这组数据,给你的编号是no.1<no.5,no.4<no.2......这样得到的答案是:4,2,5,1,3。这里的数字标识的还是编号no.x,而正确结果是2,4,5,3,1。
如果用贪心的思想:我们知道了位置上的数字的大小关系,那么我们找到最大的一个数,把它赋值n,在通过它找到比他小但是除它以外最大的所有的数,然后把他们中编号最大的找出,赋值n-1..........,用贪心很难找到他的确切的起点,所以倒着来。
#include<iostream> #include<cstring> #include<cstdio> #include<queue> using namespace std; int n,m; int map[200+5][200+5]; int ind[200+5]; int id[200+5]; int ans[200+5]; struct node { int x; friend bool operator < (node a,node b) { return a.x<b.x; } }e; void Input() { scanf("%d %d",&n,&m); memset(map,0,sizeof(map)); memset(ind,0,sizeof(ind)); for(int i=1;i<=m;i++) { int a,b; scanf("%d %d",&a,&b); if(map[b][a]) continue; map[b][a]=1; ind[a]++; } } int top_sort() { int top=n; priority_queue<node>q; while(!q.empty()) q.pop(); for(int i=1;i<=n;i++) { if(!ind[i]) { e.x=i; q.push(e); } } while(!q.empty()) { e=q.top(); q.pop(); ans[e.x]=top--; for(int i=1;i<=n;i++) { if(map[e.x][i]) { if(--ind[i]==0) { node k; k.x=i; q.push(k); } } } } return top==0; } void treatment() { if(!top_sort()) { printf("-1\n"); return; } for(int i=1;i<=n;i++) { printf("%d%c",ans[i],i==n?'\n':' '); } } int main() { int t; scanf("%d",&t); while(t--) { Input(); treatment(); } return 0; }