题意:糟糕的事情发生啦,现在大家都忙着逃命。但是逃命的通道很窄,大家只能排成一行。现在有n个人,从1标号到n。同时有一些奇怪的约束条件,每个都形如:a必须在b之前。同时,社会是不平等的,这些人有的穷有的富。1号最富,2号第二富,以此类推。有钱人就贿赂负责人,所以他们有一些好处。负责人现在可以安排大家排队的顺序,由于收了好处,所以他要让1号尽量靠前,如果此时还有多种情况,就再让2号尽量靠前,如果还有多种情况,就让3号尽量靠前,以此类推。那么你就要安排大家的顺序。我们保证一定有解。
链接:点我
题目要求要求在满足约束条件的情况下,使小的序号尽力靠前。
坑点就在这里,小的序号尽量靠前并不是代表字典序,它要求多种情况时,先使1靠前(可能1只能在第2或第3位 那么就要使它在第2位),其次2,3。。而不是在当前情况下,该位最小是哪个就输出哪个
所以直接拓扑排序,或者优先队列都是错的,因为这样都只能保证字典序最小。可以参考代码后面的样例理解
正确做法应该是 反向建图后,用最大值优先的优先队列来拓扑排序,这样能保证在可能的情况下,先选最大的,把最小的留到最后选。
14 34 2 3 2 4 1 应该输出4132
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<queue> #include<map> using namespace std; #define MOD 1000000007 #define pb(a) push_back(a) const int INF=0x3f3f3f3f; const double eps=1e-5; typedef long long ll; #define cl(a) memset(a,0,sizeof(a)) #define ts printf("*****\n"); const int MAXN=30010; int n,m,tt,cnt; int ans[MAXN]; int in[MAXN]; struct cmp { bool operator ()(int &a,int &b) { return a<b; //大的优先出队 } }; vector<int> vc[MAXN]; void topo() { priority_queue<int,vector<int>,cmp> q; for(int i=1;i<=n;i++) { if(in[i]==0) q.push(i); } while(!q.empty()) { int x=q.top(); q.pop(); ans[cnt++]=x; for(int i=0;i<vc[x].size();i++) { in[vc[x][i]]--; if(in[vc[x][i]]==0) q.push(vc[x][i]); } } } int main() { int i,j,k; #ifndef ONLINE_JUDGE freopen("1.in","r",stdin); #endif scanf("%d",&tt); while(tt--) { scanf("%d%d",&n,&m); for(i=0;i<=n;i++) { vc[i].clear(); } cl(in); cl(ans); int a,b; for(i=0;i<m;i++) { scanf("%d%d",&a,&b); vc[b].pb(a); in[a]++; } cnt=0; topo(); printf("%d",ans[n-1]); for(i=n-2;i>=0;i--) { printf(" %d",ans[i]); } printf("\n"); } }
时间: 2024-10-10 23:24:10