【題目大意】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 }