• BZOJ.2437.[NOI2011]兔兔与蛋蛋游戏(二分图博弈 匈牙利)


    题目链接

    首先空格的移动等价于棋子在黑白格交替移动(设起点移向白格就是黑色),且不会走到到起点距离为奇数的黑格、到起点距离为偶数的白格(删掉就行了),且不会重复走一个格子。
    (然后策略就同上题了,只不过第一步是走棋子)
    还是考虑二分图最大匹配。如果起点不一定在最大匹配上,先手走到最大匹配点,后手沿最大匹配边走,先手要么无法走要么回到刚刚的情况,即先手必败(最大匹配是一条奇数长路径)。
    反之,如果起点一定在最大匹配上,先手必胜。
    判断一个点是否一定在最大匹配上可以先求一遍,再对非匹配点DFS。但是本题有多次移动,相当于删掉之前的点再求最大匹配。
    如果删掉的点一定在最大匹配上,那么移动前该人必胜。
    判断删的点是否一定在最大匹配中:首先当前在最大匹配中,其次删掉这个点x后,没有新的增广路(match[x]找不到新匹配)。

    删点后记得清空连着的点的link啊。

    //1212kb	36ms
    #include <cstdio>
    #include <cctype>
    #include <algorithm>
    //#define gc() getchar()
    #define MAXIN 300000
    #define gc() (SS==TT&&(TT=(SS=IN)+fread(IN,1,MAXIN,stdin),SS==TT)?EOF:*SS++)
    const int N=1605,M=N<<2;
    
    int n,m,mp[50][50],id[50][50],Enum,H[N],nxt[M],to[M],lk[N],Time,vis[N];
    bool ban[N],ans[2005];
    char IN[MAXIN],*SS=IN,*TT=IN;
    
    inline int read()
    {
    	int now=0;register char c=gc();
    	for(;!isdigit(c);c=gc());
    	for(;isdigit(c);now=now*10+c-'0',c=gc());
    	return now;
    }
    inline void AE(int u,int v)
    {
    	to[++Enum]=v, nxt[Enum]=H[u], H[u]=Enum;
    	to[++Enum]=u, nxt[Enum]=H[v], H[v]=Enum;
    }
    bool OK(int x)
    {
    	vis[x]=Time;
    	for(int i=H[x],v; i; i=nxt[i])
    		if(vis[v=to[i]]!=Time && !ban[v])
    		{
    			vis[v]=Time;
    			if(!lk[v]||OK(lk[v])) return lk[v]=x,lk[x]=v,1;
    		}
    	return 0;
    }
    
    int main()
    {
    	n=read(),m=read(); int x=0,y=0;
    	for(int i=1; i<=n; ++i)
    	{
    		register char c=gc();
    		for(; c!='X'&&c!='O'&&c!='.'; c=gc());
    		for(int j=1; j<=m; ++j,c=gc())
    			if(c=='X') mp[i][j]=1;//black
    			else if(c=='O') mp[i][j]=0;//white
    			else x=i, y=j, mp[i][j]=1;
    	}
    	int f=(x+y)&1,tot=0;
    	for(int i=1; i<=n; ++i)
    		for(int j=1; j<=m; ++j)
    			if(mp[i][j]^f^((i+j)&1))//f^is_black^(i+j)&1
    				id[i][j]=++tot;
    	for(int i=1; i<=n; ++i)
    		for(int j=1; j<=m; ++j)
    		{
    			if(!id[i][j]) continue;//!
    			if(id[i+1][j]) AE(id[i][j],id[i+1][j]);
    			if(id[i][j+1]) AE(id[i][j],id[i][j+1]);
    		}
    	for(int i=1; i<=tot; ++i) if(!lk[i]/*!*/) ++Time, OK(i);
    	int K=read()<<1;
    	for(int i=1,p; i<=K; ++i)
    	{
    		ban[p=id[x][y]]=1;
    		if(lk[p]) ++Time, lk[lk[p]]=0/*清空!*/, ans[i]=!OK(lk[p]);//(x,y)是否是必胜态 
    		x=read(), y=read();
    	}
    	int res=0;
    	for(int i=1; i<=K; i+=2) if(ans[i]&&ans[i+1]) ++res;
    	printf("%d
    ",res);
    	for(int i=1; i<=K; i+=2) if(ans[i]&&ans[i+1]) printf("%d
    ",i+1>>1);
    
    	return 0;
    }
    
  • 相关阅读:
    集成学习值Adaboost算法原理和代码小结(转载)
    集成学习原理小结(转载)
    2019阿里校招测评题,光明小学完全图最短路径问题(python实现)
    第八节、图片分割之GrabCut算法、分水岭算法
    Scala2.11.8 spark2.3.1 mongodb connector 2.3.0
    spark 实现动态日期读取
    Idea 201601注册码
    linux下的crontab服务
    spark MySQL jar 包
    scala 日期格式转换
  • 原文地址:https://www.cnblogs.com/SovietPower/p/9592769.html
Copyright © 2020-2023  润新知