BZOJ 1433 二分图上的博弈

首先对网格染色,发现是而二分图。

那么即在二分图上选一个起点走过的点无法再走,最后无路可走就输了。

如果起点必在最大匹配中,先手必赢。

如果起点不一定在最大匹配中(包括不可能在),后手必赢。网上有解释。

因为写二分图不怎么熟练,所以还是用网络流吧。

找的就是可行的和不在最大匹配中点。建边要用单向边。

从源点和汇点开始Dfs。假如从左边开始那么先扫到右边后又扫到左边。那么那个点就是可行点。

  1 #include <iostream>
  2 #include <cstring>
  3 #include <cstdio>
  4 #include <algorithm>
  5 using namespace std;
  6 const int Maxn=10010;
  7 const int Inf=0x3f3f3f3f;
  8 int n,m,S,T,g[110][110],Color[Maxn],head[Maxn],Level[Maxn],Q[Maxn],u,v,cnt,cur[Maxn],Ans[Maxn],ans;
  9 bool vis[Maxn];
 10 struct Node{int to,next,w;}edge[1000010];
 11 const int dx[4]={0,0,1,-1};
 12 const int dy[4]={1,-1,0,0};
 13 inline int Id(int x,int y) {return (x-1)*m+y;}
 14 inline bool Check(int u,int v) {return ((u<=n&&u>=1)&&(v<=m&&v>=1));}
 15 inline int Min(int x,int y) {return x>y?y:x;}
 16 inline void ADD(int u,int v,int w)
 17 {edge[cnt].to=v;edge[cnt].next=head[u];edge[cnt].w=w;head[u]=cnt++;}
 18 inline void Add(int u,int v,int w) {ADD(u,v,w);ADD(v,u,0);}
 19 bool Bfs()
 20 {
 21     memset(Level,-1,sizeof(Level));
 22     Level[S]=0; Q[1]=S; int l=1,r=1;
 23     while (l<=r)
 24     {
 25         int u=Q[l++];
 26         for (int i=head[u];i!=-1;i=edge[i].next)
 27             if (Level[edge[i].to]==-1 && edge[i].w>0)
 28             {
 29                 Level[edge[i].to]=Level[u]+1;
 30                 Q[++r]=edge[i].to;
 31             }
 32     }
 33     if (Level[T]==-1) return false;
 34     return true;
 35 }
 36 int Find(int u,int low)
 37 {
 38     if (u==T || low==0) return low;
 39     int cap=0;
 40     for (int i=cur[u];i!=-1;i=edge[i].next)
 41         if (edge[i].w>0 && Level[edge[i].to]==Level[u]+1)
 42         {
 43             int tmp=Find(edge[i].to,Min(low,edge[i].w));
 44             if (tmp==0) continue;
 45             low-=tmp,cap+=tmp;
 46             edge[i].w-=tmp,edge[i^1].w+=tmp;
 47             if (edge[i].w>0) cur[u]=i;
 48         }
 49     if (cap) return cap;
 50     Level[u]=-1;
 51     return 0;
 52 }
 53 void Dfs(int u,int c)
 54 {
 55     vis[u]=true;
 56     if (Color[u]==c && u!=S && u!=T) Ans[++ans]=u;
 57     for (int i=head[u];i!=-1;i=edge[i].next)
 58         if (edge[i].w==c && !vis[edge[i].to]) Dfs(edge[i].to,c);
 59 }
 60
 61 void Get_Ans()
 62 {
 63     memset(vis,false,sizeof(vis)),Dfs(S,1);
 64     memset(vis,false,sizeof(vis)),Dfs(T,0);
 65 }
 66 int main()
 67 {
 68     // freopen("c.in","r",stdin);
 69     // freopen("c.out","w",stdout);
 70     scanf("%d%d",&n,&m);
 71     for (int i=1;i<=n;i++)
 72         for (int j=1;j<=m;j++)
 73         {
 74             char ch=getchar();
 75             while (ch!=‘.‘ && ch!=‘#‘) ch=getchar();
 76             if (ch==‘.‘) g[i][j]=1;
 77             if (ch==‘#‘) g[i][j]=0;
 78         }
 79     S=0,T=Id(n,m)+1;
 80     memset(head,-1,sizeof(head));
 81     for (int i=1;i<=n;i++)
 82         for (int j=1;j<=m;j++)
 83             if (g[i][j])
 84             {
 85                 if (!((i+j)&1))
 86                 {
 87                     Add(S,Id(i,j),1);
 88                     Color[Id(i,j)]=true;
 89                     for (int k=0;k<4;k++)
 90                     {
 91                         int u=i+dx[k],v=j+dy[k];
 92                         if (!Check(u,v)) continue;
 93                         if (g[u][v]) Add(Id(i,j),Id(u,v),1);
 94                     }
 95                 }
 96                 else Add(Id(i,j),T,1);
 97             }
 98     // for (int i=0;i<cnt;i++) printf("%d ",edge[i].to); puts("");
 99     // for (int i=0;i<cnt;i++) printf("%d ",edge[i].w);puts("");
100     // for (int i=1;i<cnt;i++) printf("%d ",edge[i].next);puts("");
101     while (Bfs())
102     {
103         for (int i=S;i<=T;i++) cur[i]=head[i];
104         Find(S,Inf);
105     }
106     Get_Ans();
107     if (!ans) puts("LOSE"); else
108     {
109         puts("WIN");
110         sort(Ans+1,Ans+ans+1);
111         for (int i=1;i<=ans;i++) printf("%d %d\n",(Ans[i]-1)/m+1,(Ans[i]-1)%m+1);
112     }
113     // if ()
114     return 0;
115 }

C++

时间: 2024-10-09 18:49:38

BZOJ 1433 二分图上的博弈的相关文章

BZOJ 1433 假期的宿舍 二分图匹配

这道题目不难,二分图匹配建模比较明显.加油吧!相信自己.(自己写的,好开心,40毫秒,比ccz略快). 尽管算法模版是抄一本书上的,但这次很明显我是背出来的.不算抄. 1 #include<cstdio> 2 #include<iostream> 3 #include<vector> 4 #include<queue> 5 #include<cstring> 6 #define rep(i,j,k) for(int i = j; i <=

(二分图匹配) bzoj 1433

1433: [ZJOI2009]假期的宿舍 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1451  Solved: 628[Submit][Status][Discuss] Description Input Output Sample Input 1 3 1 1 0 0 1 0 0 1 1 1 0 0 1 0 0 Sample Output ˆ ˆ HINT 对于30% 的数据满足1 ≤ n ≤ 12.对于100% 的数据满足1 ≤ n ≤

Bzoj 4950 (二分图最大匹配)

Description 那是春日里一个天气晴朗的好日子,你准备去见见你的老朋友Patrick,也是你之前的犯罪同伙.Patrick在编程竞赛 上豪赌输掉了一大笔钱,所以他需要再干一票.为此他需要你的帮助,虽然你已经金盆洗手了.你刚开始很不情愿, 因为你一点也不想再回到那条老路上了,但是你觉得听一下他的计划也无伤大雅.在附近的一个仓库里有一批货物, 包含一些贵重的消费性部件,Patrick企图从中尽可能多地偷些东西出来.这意味着要找一条进去的路,弄晕安保人 员,穿过各种各样的激光射线,你懂的,都是

BZOJ 1059 &amp; 二分图匹配

题意: 判断一个黑白染色的棋盘能否通过交换行或列使对角线上都是黑色. SOL: 真是有点醉...这种问题要么很神要么很水...第一眼感觉很水但就是不造怎么做...想了10分钟怎么感觉就是判断个数够不够n呢然后就蹦出了一个反例...然后就忍不了百度= =... 二分图匹配真是瞎了眼...然后发现好神又好水... 显然的同一行无论怎么交换都是同一行---->根本就没往这上面想...同一列永远都是同一列,那么只要判断有多少不同行又不同列的就好了...枚举有点虚,那么就匹配吧!按照行列建图,恩就是这样.

BZOJ 4808 二分图最大独立集

思路: 棋盘是个二分图 那就把一个可以走的白点  向所有可以走的黑点连边 跑一个最大匹配   (匹配上了就代表这两个点不能共存) 最大独立集=sum-最大匹配 //By SiriusRen #include <queue> #include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int N=222,M=N*N*21; int n,m,a[N][N

BZOJ 1299 [LLH邀请赛]巧克力棒 博弈(NIM游戏)+构造

题意:链接 方法:博弈+构造 解析: 神题没想到咋做,看完wyf大爷说的话才懂 这道题的题意就是有n堆石子,之后你每次操作有两种做法 第一种是在已经建立的nim游戏上进行nim游戏. 第二种是在未被选的堆中选取若干堆加入这个nim游戏中. 所以这怎么做? 我一直尝试去建立一个必败态,不过可能我走的方法过多的考虑了将这道题转变为nim游戏套nim游戏而最终走入死胡同,不会做了. 然而这道题的必败态可以这么建:如果是先手的话,我可以建立出来一个异或和为0的nim游戏,此时后者有两种做法,第一种是在该

BZOJ 4025 二分图 分治+并查集

题目大意:给定一张n个点的图,有m条边,T个时间段,每条边只存在于(st,ed]这些时间段,求每个时间段内这个图是否是二分图 分治并查集大法好 定义Solve(x,y,E)为当前处理的区间为[x,y],E为所有存在时间为[x,y]的子集的边的集合 那么对于E中的每一条边(u,v),讨论: 若当前边的存在时间为[x,y],则在并查集上判断是否出现奇环 如果出现,[x,y]内的所有时刻都一定不是二分图,输出答案即可 如果不出现,在并查集中连接(u,v) 否则判断存在时间和mid的关系讨论扔进左区间还

在二分图上加一条边与其逆问题

二分图定义:https://en.wikipedia.org/wiki/Bipartite_graph 考虑正问题,二分图的一个充要条件是图中所有的环都是偶环 * . 从而加的边只能形成一个偶环,我们可以将二分图黑白染色,分为两个集合,这样合法边只有两种 1.横跨两个联通快的边. 2.在一个联通块且两个端点异色的边. 这显然是正确的,求有多少个这样的边,分上面两种情况进行分类即可,时间复杂度 O(n). 接下来考虑逆问题,如何在图上删除一条边使得这个图变成二分图. 如果这个图本来就是二分图,删一

[BZOJ]1045 圆上的整点(HAOI2008)

数学题第二弹! Description 求一个给定的圆(x^2+y^2=r^2),在圆周上有多少个点的坐标是整数. Input 一个正整数r. Output 整点个数. Sample Input 4 Sample Output 4 HINT r<=2000 000 000 Solution 小C不想写题解啊啊啊啊!!!! 题解在这里啊啊啊啊!!!!(看完记得投币!!!!) 我爱数学啊啊啊啊!!!! 开玩笑的,还是说一说题解吧. 相信如果你认真看完了上面那个视频的前25min,心里肯定已经有不下一