题意:N个点,给出M条两个点u、v,满足u比值小。给这N个点编号,要求排在前的比排在后的质量小,且编号不重复。求每点能得到最小编号的编号方法。
分析:用拓扑排序求解。
用优先队列来存待标记的点,编号大的点优先出队列,然后从大到小依次标记(编号小的优先肯定是错的,当时wa死了)。
若求不出拓扑排序则答案无解。
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<vector> #include<queue> typedef long long LL; using namespace std; const int maxn =5e2+5; const int maxm = 4e4+5; struct Edge{ int v,next; }edge[maxm]; int head[maxn],tot,cnt; int ind[maxn]; void init() { memset(ind,0,sizeof(ind)); memset(head,-1,sizeof(head)); tot=0; } void AddEdge(int u,int v) { edge[tot] = (Edge){v,head[u]}; head[u] = tot++; } int ans[maxn]; bool topo(int n) { cnt=n; priority_queue<int> Q; for(int i =1;i<=n;++i){ if(!ind[i]){ Q.push(i); } } while(!Q.empty()){ int u = Q.top() ;Q.pop(); ans[u] = cnt--; for(int i=head[u];~i;i=edge[i].next){ int v = edge[i].v; ind[v]--; if(!ind[v]){ Q.push(v); } } } if(cnt!=0) return false; else return true; } int main() { #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif int N,M,m,q,u,v,cas=1; int T; scanf("%d",&T); while(T--){ init(); bool flag = false; scanf("%d%d",&N,&M); while(M--){ scanf("%d%d",&v,&u); //if(u==v) flag = true; AddEdge(u,v); ind[v]++; } if(flag || !topo(N)) printf("-1 "); else{ for(int i=1;i<N;++i){ printf("%d ",ans[i]); } printf("%d ",ans[N]); } } return 0; }