DMOJ IOI '17 P3 - Toy Train【拓撲排序】
阿新 • • 發佈:2019-05-03
ack () sin .net 參考 emp 全部 article namespace
傳送:https://dmoj.ca/problem/ioi17p3
參考:https://blog.csdn.net/qq_27327327/article/details/80711824
妙啊……首先題意就是走到一個包含充電點的環裏就能贏
因為出度至少是1,所以如果所有點都能到充電點那麽全部是先手必勝;否則,不能到充點電的點以及一定能到這些點的點就一定是先手必敗(能到的不是先手必勝,因為可能到了之後再出去進入別的環)
能到充點電的點是A支配並且能到至少一個充點電的點或B支配只能到充電點的點,每次求出這個集合,判斷如果是全集就退出,否則用補集找到先手必敗點刪去,然後再對剩下不確定的點做上述操作即可
#include<iostream> #include<cstdio> #include<vector> #include<queue> using namespace std; const int N=5005; int n,m; vector<int>e[N],e2[N]; vector<int>wk(int fl,vector<int>a,vector<int>r,vector<int>b) { vector<int>ans(n),d(n); queue<int>q; for(int i=0;i<n;i++) if(r[i]&&b[i]) q.push(i),ans[i]=1; for(int i=0;i<n;i++) for(int j=0;j<e[i].size();j++) if(b[e[i][j]]) { if(a[i]^fl) d[i]++; else d[i]=1; } while(!q.empty()) { int u=q.front(); q.pop(); for(int i=0;i<e2[u].size();i++) if(!ans[e2[u][i]]&&b[e2[u][i]]) if(!(--d[e2[u][i]])) { ans[e2[u][i]]=1; q.push(e2[u][i]); } } return ans; } vector<int> who_wins(vector<int>a,vector<int>r,vector<int>u,vector<int>v) { n=a.size(),m=u.size(); for(int i=0;i<m;i++) e[u[i]].push_back(v[i]),e2[v[i]].push_back(u[i]); vector<int>ans(n); for(int i=0;i<n;i++) ans[i]=1; while(1) { int fl=1; vector<int>b1=wk(1,a,r,ans); for(int i=0;i<n;i++) if(ans[i]&&!b1[i]) fl=0; if(fl) return ans; for(int i=0;i<n;i++) b1[i]^=1; vector<int>b2=wk(0,a,b1,ans); for(int i=0;i<n;i++) if(b2[i]) ans[i]=0; } return ans; }
DMOJ IOI '17 P3 - Toy Train【拓撲排序】