loj536 「LibreOJ Round #6」花札
一眼二分图博弈,于是我们可以拿到69分的好成绩。
二分图暴力加边的数目是O(n^2)的,于是我们考虑网络流优化建图,将alice的每个牌向其的颜色和编号节点连边,bob的每个牌由其颜色和编号节点向其连边,之后在分别和源汇连边,我们发现我们现在是要找哪些点在所有最大流的方案中都有流量流入,我们发现这样的点在跑完最大流后的残留网络上一定是源点所不能到达的,因为否则我们可以通过把这条路径以及S->i的边取反即可得到反例,所以我们直接跑一遍最大流再在残留网络上bfs一遍即可。
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <cmath> 6 #include <queue> 7 #define N 100500 8 #define inf 0x7fffffff 9 using namespace std; 10 int e=2,head[N]; 11 struct edge{ 12 int u,v,f,next; 13 }ed[N<<3]; 14 void add(int u,int v,int f){ 15 ed[e].u=u;ed[e].v=v;ed[e].f=f; 16 ed[e].next=head[u];head[u]=e++; 17 ed[e].u=v;ed[e].v=u;ed[e].f=0; 18 ed[e].next=head[v];head[v]=e++; 19 } 20 int dep[N],S,T; 21 bool bfs(){ 22 memset(dep,0,sizeof dep); 23 queue<int> q;q.push(S);dep[S]=1; 24 while(!q.empty()){ 25 int x=q.front();q.pop(); 26 for(int i=head[x];i;i=ed[i].next){ 27 if(ed[i].f&&!dep[ed[i].v]){ 28 dep[ed[i].v]=dep[x]+1; 29 q.push(ed[i].v); 30 } 31 } 32 } 33 return dep[T]!=0; 34 } 35 int dfs(int x,int f){ 36 if(x==T||!f)return f; 37 int ans=0; 38 for(int i=head[x];i;i=ed[i].next){ 39 if(ed[i].f&&dep[ed[i].v]==dep[x]+1){ 40 int nxt=dfs(ed[i].v,min(f,ed[i].f)); 41 ans+=nxt,f-=nxt;ed[i].f-=nxt,ed[i^1].f+=nxt; 42 if(!f)break; 43 } 44 } 45 if(!ans)dep[x]=-1; 46 return ans; 47 } 48 int n,m,n1,n2,x[N],y[N]; 49 int main(){ 50 // freopen("test.in","r",stdin); 51 scanf("%d%d",&n,&m); 52 scanf("%d",&n1); 53 for(int i=1;i<=n1;i++)scanf("%d%d",&x[i],&y[i]); 54 scanf("%d",&n2); 55 for(int i=n1+1;i<=n1+n2;i++)scanf("%d%d",&x[i],&y[i]); 56 S=n1+n2+n+m+1;T=S+1; 57 for(int i=1;i<=n1;i++){ 58 add(S,i,1); 59 add(i,n1+n2+x[i],1); 60 add(i,n1+n2+n+y[i],1); 61 } 62 for(int i=n1+1;i<=n1+n2;i++){ 63 add(i,T,1); 64 add(n1+n2+x[i],i,1); 65 add(n1+n2+n+y[i],i,1); 66 } 67 while(bfs())dfs(S,inf); 68 for(int i=1;i<=n1;i++){ 69 if(dep[i])puts("0"); 70 else puts("1"); 71 } 72 }
人生如梦亦如幻 朝如晨露暮如霞。