【题目大意】html
是要求N个点的一个拓扑序,且知足如下条件:编号1的位置尽量靠前,在知足全部限制,编号2的位置尽量靠前,以此类推。c++
【思路】算法
一开始以为优先队列维护一下拓扑就行了。然而样例告诉咱们是不能够的。若是限制条件是:
5 2
4 3post
最后出来的会是1-4-3-5-2,而答案应该是1-5-2-4-3。spa
由此能够发现,若是正向拓扑出来的是“字典序最小”,而不是“编号小的尽量靠前”。code
因此逆向拓扑。htm
证实……算了困了,改天再纠结吧。丢个连接存个档。❀blog
不妨认为咱们这样获得的不是最优解,那么令这样获得的序列为a,而后最优解是b。 咱们从后往前开始找到第一位两个序列不一样的一位设为k,那么a[k]!=b[k],且a[k]>b[k]。(由a的构造方式可知)(先假设这个k存在,再证出矛盾) 再设a[k]出现的b的p位置,即b[p]=a[k]。再设b[p] b[p+1]……b[k]这个子序列为C。 那么b[p]必定不是C中的最小元素,由于有b[k]<b[p]=a[k]。 而后不妨设b[q]为C的最小元素。而后咱们把b[p]移到b[k]的位置,获得序列bb。 若是bb合法的话,那么咱们就获得了一个比b优的解,这与b是最优解矛盾。 (由于b[q]的位置前移了一位,咱们要求编号小的尽量靠前) 但bb显然是合法的。由于在a序列中k以及后面的是合法的,那么b后面也这么作必定也是合法的。 因此必定不存在某个k,使得a[k]!=b[k]。也就是说a=b。 因此算法正确性得证。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int MAXN=100000+50; 4 int n,m,in; 5 vector<int> E[MAXN]; 6 priority_queue<int> que; 7 int ans[MAXN],inn[MAXN]; 8 9 void init() 10 { 11 scanf("%d%d",&n,&m); 12 memset(inn,0,sizeof(inn)); 13 for (int i=1;i<=n;i++) vector<int>().swap(E[i]); 14 for (int i=0;i<m;i++) 15 { 16 int u,v; 17 scanf("%d%d",&u,&v); 18 inn[u]++; 19 E[v].push_back(u); 20 } 21 } 22 23 void solve() 24 { 25 while (!que.empty()) que.pop(); 26 ans[0]=0; 27 for (int i=1;i<=n;i++) if (!inn[i]) que.push(i); 28 while (!que.empty()) 29 { 30 int u=que.top();que.pop(); 31 ans[++ans[0]]=u; 32 for (int i=0;i<E[u].size();i++) 33 { 34 int v=E[u][i]; 35 inn[v]--; 36 if (!inn[v]) que.push(v); 37 } 38 } 39 if (ans[0]<n) puts("Impossible!"); 40 else 41 { 42 for (int i=ans[0];i>=1;i--) printf("%d ",ans[i]); 43 printf("\n"); 44 } 45 } 46 47 int main() 48 { 49 int T; 50 scanf("%d",&T); 51 while (T--) 52 { 53 init(); 54 solve(); 55 } 56 return 0; 57 }