1. 程式人生 > >遊戲 - 博弈論

遊戲 - 博弈論

題目大意:
給你一張DAG,每個點有個係數k[x],多次詢問,每次詢問給你每個點的點權。
兩個人輪流操作,每次操作形如選擇一個點權大於0並且有出邊的點x,使其點權val[x]–,並在其出邊中選擇恰好k[x]個點(可以重複)點權++。不能操作者輸,問先手是否必勝。記所有點出度的最大值是v。 n 100 , m

1700 , q 1000 , v 17 ,
T 20 n\le100,m\le1700,q\le1000,v\le17,T\le20
題解:
考慮k=1怎麼做,發現就是個樸素的DAG上的遊戲。k>1和k=1類似,只不過後繼狀態變多了,並且後繼狀態是一堆狀態的並而已。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1) #define lint long long #define ull unsigned lint #define db long double #define pb push_back #define mp make_pair #define fir first #define sec second #define gc getchar() #define N 110 #define S (1<<18) #define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl using namespace std; typedef pair<int,int> pii; typedef set<int>::iterator sit; inline int inn() { int x,ch;while((ch=gc)<'0'||ch>'9'); x=ch^'0';while((ch=gc)>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^'0');return x; } int v[S],vis[S],sz[S],lb[S],id[S],d[N],lst[N],ls[S]; vector<int> g[N];queue<int> q;int sg[N],k[N]; inline int toposort(int n) { memset(d,0,sizeof(int)*(n+1)); rep(x,1,n) Rep(i,g[x]) d[g[x][i]]++; while(!q.empty()) q.pop();int t=0; rep(i,1,n) if(!d[i]) q.push(i); while(!q.empty()) { int x=q.front();q.pop(),lst[++t]=x; Rep(i,g[x]) if(!(--d[g[x][i]])) q.push(g[x][i]); } return 0; } inline int ok(int c,int k) { if(c>k) return 0;return ((c-k)&1)==0; } inline int getsg(int n) { for(int t=n;t;t--) { int x=lst[t],all=(1<<((int)g[x].size()))-1,p=0; if((int)g[x].size()==0) { sg[x]=0;continue; } Rep(i,g[x]) id[1<<i]=g[x][i];v[0]=0; rep(s,1,all) v[s]=v[s^lb[s]]^sg[id[lb[s]]]; rep(s,0,all) if(ok(sz[s],k[x])) vis[ls[++p]=v[s]]=1; for(sg[x]=0;vis[sg[x]];sg[x]++);for(;p;vis[ls[p--]]=0); // debug(x)sp,debug(sg[x])ln; } return 0; } int main() { int all=(1<<17)-1; rep(i,1,all) lb[i]=(i&-i),sz[i]=sz[i^lb[i]]+1; for(int T=inn(),curT=1,u,v;curT<=T;printf("\n"),curT++) { int n=inn(),m=inn();rep(i,1,n) g[i].clear(); rep(i,1,m) u=inn()+1,v=inn()+1,g[u].pb(v); rep(i,1,n) k[i]=inn();toposort(n),getsg(n); printf("Game#%d:\n",curT); for(int curQ=1,Q=inn();curQ<=Q;curQ++) { int ans=0;printf("Round#%d: ",curQ); rep(i,1,n) ans^=sg[i]*(inn()&1); printf(ans?"WINNING\n":"LOSING\n"); } } return 0; }