zoukankan      html  css  js  c++  java
  • 【LOJ#536】「LibreOJ Round #6」花札

    题目链接

    题目描述

    「UniversalNO」的规则如下:每张牌有一种颜色和一个点数。两个人轮流出牌,由 Alice 先手,最开始牌堆为空,出的人可以出任意牌(放到牌堆顶),之后出的牌必须和当时牌堆顶的牌的颜色或点数至少有一个相同。有牌可出者必须出,无牌可出者输。

    Alice 和 Shinobu 玩了几局后觉得原来的规则太依靠运气,于是她们加了一个新玩法:Alice 出了第一张之后,两个人立即交换手里的牌,然后从 Alice 开始继续按原来的规则进行游戏。当然,这次 Alice 出的牌必须和她刚开始出的颜色或点数至少有一个相同。

    交换之后两人都知道对方的手牌(就是开局时自己的手牌),于是就有必胜策略了。

    现在已知 Alice 和 Shinobu 手里一开始的牌,请你求出对于 Alice 第一次出牌的每种情况,谁有必胜策略。

    Sol

    不难看出出了一张牌后另一个人能够出的牌是可以事先知道的。
    那么这就形成一个二分图。
    博弈过程相当于是一开始在先手的点上放了一个棋子,然后每次轮流沿着出边走,不能走的人失败。

    这是一个经典的二分图博弈模型
    先手必胜当且仅当棋子所在点一定在最大匹配中。

    判断方法:
    跑网络流,要求源点到这个点有流量且这个点没有被分割在源点集合。

    code:

    #include<bits/stdc++.h>
    using namespace std;
    #define Set(a,b) memset(a,b,sizeof(a))
    template<class T>inline void init(T&x){
    	x=0;char ch=getchar();bool t=0;
    	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') t=1;
    	for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<1)+(x<<3)+(ch-48);
    	if(t) x=-x;return;
    }typedef long long ll;
    const int N=4e4+10;
    const int MAXN=2e5+10;
    const int MAXM=2e6+10;
    int m,c,n1,n2;
    struct edge{
    	int to,next,cap;
    }a[MAXM<<2];
    int head[MAXN],cnt=0,cur[MAXN],d[MAXN];
    inline void add(int x,int y,int z){a[cnt]=(edge){y,head[x],z};head[x]=cnt++;}
    inline void add_edge(int x,int y,int z){add(x,y,z),add(y,x,0);}
    int X1[N],X2[N],Y1[N],Y2[N];
    int idnum[N],idcol[N],idshi[N];
    int S=0,T;
    queue<int> Q;
    int dfs(int u,int flow){
    	if(u==T) return flow;
    	int res=flow;
    	for(int v,&i=cur[u];~i;i=a[i].next) {
    		v=a[i].to;if(!a[i].cap||d[v]!=d[u]+1) continue;
    		int f=dfs(v,min(res,a[i].cap));
    		a[i].cap-=f,a[i^1].cap+=f;
    		res-=f;if(!f) d[v]=0;
    		if(!res) break;
    	}
    	return flow-res;
    }
    inline bool bfs(){
    	for(int i=S;i<=T;++i) d[i]=0;d[S]=1;
    	while(!Q.empty()) Q.pop();Q.push(S);
    	while(!Q.empty()) {
    		int u=Q.front();Q.pop();
    		for(int v,i=head[u];~i;i=a[i].next) {
    			v=a[i].to;if(!a[i].cap||d[v]) continue;
    			d[v]=d[u]+1;if(v==T) return 1;Q.push(v);
    		}
    	}
    	return d[T];
    }
    inline void Dinic(){
    	int fl=0;
    	while(bfs()) memcpy(cur,head,sizeof(cur)),fl+=dfs(S,1e9);
    	return;
    }
    int ans[N];
    int main()
    {
    	init(m),init(c);init(n1);
    	Set(head,-1);for(int i=1;i<=n1;++i) init(X1[i]),init(Y1[i]);
    	init(n2);int h=n1;
    	for(int i=1;i<=n2;++i) idshi[i]=++h;
    	for(int i=1;i<=m;++i) idnum[i]=++h;
    	for(int i=1;i<=c;++i) idcol[i]=++h;
    	T=++h;
    	for(int i=1;i<=n1;++i) add_edge(S,i,1),add_edge(i,idnum[X1[i]],1),add_edge(i,idcol[Y1[i]],1);
    	for(int i=1;i<=n2;++i) init(X2[i]),init(Y2[i]),add_edge(idshi[i],T,1),add_edge(idnum[X2[i]],idshi[i],1),add_edge(idcol[Y2[i]],idshi[i],1);
    	Dinic();bfs();
    	for(int v,i=head[S];~i;i=a[i].next) {v=a[i].to;if(v>0&&v<=n1&&!a[i].cap&&!d[v]) ans[v]=1;}
    	for(int i=1;i<=n1;++i) puts(ans[i]? "1":"0");
    	return 0;
    }
    
    
  • 相关阅读:
    JavaScript数组升降序排列、最大值、最小值等
    css3箭头
    隐藏显示
    最后一个 last-of-type
    jquery函数封装
    为什么要使用rem
    Git的使用--如何将本地项目上传到Github
    jQuery判断是否选中
    数组索引赋值
    HTML中input和button设置同样高度却不能等高的原因
  • 原文地址:https://www.cnblogs.com/NeosKnight/p/11122991.html
Copyright © 2011-2022 走看看