那個問一下有人可以解釋以下這個做法嘛,看不太懂QwQ~
Description
有一個n個點n條邊的有向圖,點的編號為從1到n。
給出一個數組p,表明有(p1,1),(p2,2),…,(pn,n)這n條單向邊,這n條邊必定構成弱連通圖。
每個點均有一個權值ai,滿足以下性質:
(1)所有ai均為非負整數;
(2)對于任意邊(i,j),有ai≠aj;
(3)對于任意i,x(0≤x<ai),均有(i,j)滿足aj=ai。
判斷這樣的圖是否存在。(“POSSIBLE”/“IMPOSSIBLE”)
Solution
(早上花了三個小時還打挫了,心態爆炸)
弱連通圖:若該有向圖所有邊為雙向邊時,滿足該圖為連通圖,則該有向圖為弱連通圖。
我們容易發現,當一個點的出度為0時,它的權值也為0。我們可以對每一條邊建反向邊,然后進行拓撲排序,每次對新圖中入度為0的點求出權值,然后刪去。
若最后有剩余的點,由于原圖中每個點的入度均為1,則這些點形成一個環,取其中任意一個點開始遍歷即可。特別地,若原圖n個點構成環,則偶環存在而奇環不存在。
下面講一下如何求出每個點的權值:
拓撲排序:
若該點在原圖中為葉子節點,則權值為0;
若不為葉子節點,則權值為原圖子節點權值中未出現的數的最小值。
環:
記錄原圖中該點不在環上的子節點權值中未出現的數的最小值a與次小值b。若該點權值為a,則下一點無限制;若該點權值為b,則下一點權值必為a。在跑環的時候,注意判斷相鄰兩點權值不相等以及子節點權值滿足條件(2)(3)即可。
Code
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<queue> 5 #include<stack> 6 using namespace std; 7 #define next _next 8 struct edge{ 9 int to,next; 10 }e[200010],g[200010]; 11 int n,ehead[200010],ghead[200010]; 12 int m=0,a[200010]={0},out[200010]={0}; 13 int val[200010]; 14 bool vis[200010]={false}; 15 queue<int>q; 16 stack<int>s[200010]; 17 bool dfs(int u,int w,int cannot){ 18 for(int i=ehead[u];~i;i=e[i].next) 19 if(vis[e[i].to]) 20 s[val[e[i].to]].push(u); 21 int v=-1; 22 for(int i=ehead[u];~i;i=e[i].next) 23 if(!vis[e[i].to]){ 24 v=e[i].to; 25 break; 26 } 27 if(v==-1){ 28 if(w==-1){ 29 for(int i=0;;i++) 30 if(s[i].top()!=u){ 31 val[u]=i; 32 break; 33 } 34 } 35 else{ 36 val[u]=w; 37 for(int i=0;i<w;i++) 38 if(s[i].top()!=u){ 39 for(int i=ehead[u];~i;i=e[i].next) 40 if(vis[e[i].to]) 41 s[val[e[i].to]].pop(); 42 return false; 43 } 44 } 45 bool ret=(val[u]!=cannot&&s[val[u]].top()!=u); 46 for(int i=ehead[u];~i;i=e[i].next) 47 if(vis[e[i].to]) 48 s[val[e[i].to]].pop(); 49 return ret; 50 } 51 if(w==-1){ 52 int flag=-1; 53 bool ret=false; 54 for(int i=0;;i++) 55 if(s[i].top()!=u){ 56 vis[u]=true; 57 if(i!=cannot) 58 ret|=dfs(v,flag,val[u]=i); 59 vis[u]=false; 60 if(flag>-1) 61 break; 62 flag=i; 63 } 64 for(int i=ehead[u];~i;i=e[i].next) 65 if(vis[e[i].to]) 66 s[val[e[i].to]].pop(); 67 return ret; 68 } 69 int flag=-1; 70 for(int i=0;i<w;i++) 71 if(s[i].top()!=u){ 72 if(flag>-1){ 73 for(int i=ehead[u];~i;i=e[i].next) 74 if(vis[e[i].to]) 75 s[val[e[i].to]].pop(); 76 return false; 77 } 78 flag=i; 79 } 80 bool ret=(w!=cannot&&s[w].top()!=u&&dfs(v,flag,val[u]=w)); 81 for(int i=ehead[u];~i;i=e[i].next) 82 if(vis[e[i].to]) 83 s[val[e[i].to]].pop(); 84 return ret; 85 } 86 int main(){ 87 memset(ehead,-1,sizeof(ehead)); 88 memset(ghead,-1,sizeof(ghead)); 89 memset(val,-1,sizeof(val)); 90 while(!q.empty())q.pop(); 91 scanf("%d",&n); 92 for(int i=0;i<=n;i++){ 93 while(!s[i].empty()) 94 s[i].pop(); 95 s[i].push(0x3f3f3f3f); 96 } 97 for(int i=1,x;i<=n;i++){ 98 scanf("%d",&x); 99 e[i]=(edge){i,ehead[x]}; 100 g[i]=(edge){x,ghead[i]}; 101 ehead[x]=ghead[i]=i; 102 a[x]++;out[x]++; 103 } 104 for(int i=1;i<=n;i++) 105 if(out[i]==0){ 106 vis[i]=true; 107 q.push(i); 108 } 109 while(!q.empty()){ 110 int u=q.front(); 111 q.pop();m++; 112 for(int i=ehead[u];~i;i=e[i].next) 113 s[val[e[i].to]].push(u); 114 for(int i=0;;i++) 115 if(s[i].top()!=u){ 116 val[u]=i; 117 break; 118 } 119 for(int i=ehead[u];~i;i=e[i].next) 120 s[val[e[i].to]].pop(); 121 for(int i=ghead[u];~i;i=g[i].next) 122 out[g[i].to]--; 123 for(int i=ghead[u];~i;i=g[i].next) 124 if(out[g[i].to]==0){ 125 vis[g[i].to]=true; 126 q.push(g[i].to); 127 } 128 } 129 if(m==n){ 130 puts("POSSIBLE"); 131 return 0; 132 } 133 if(m==0){ 134 puts(n&1?"IMPOSSIBLE":"POSSIBLE"); 135 return 0; 136 } 137 for(int i=1;i<=n;i++) 138 if(!vis[i]){ 139 puts(dfs(i,-1,-1)?"POSSIBLE":"IMPOSSIBLE"); 140 return 0; 141 } 142 return 0; 143 }
(話說環套樹的題是真的煩[○・`Д′・ ○])