[匈牙利算法][博弈] Luogu P1971 兔兔与蛋蛋

题目描述

这些天,兔兔和蛋蛋喜欢上了一种新的棋类游戏。 这个游戏是在一个n行m列的棋盘上进行的。游戏开始之前,棋盘上有一个格子是空的,其它的格子中都放置了一枚棋子,棋子或者是黑色,或者是白色。 每一局游戏总是兔兔先操作,之后双方轮流操作,具体操作为:

兔兔每次操作时,选择一枚与空格相邻的白色棋子,将它移进空格。

蛋蛋每次操作时,选择一枚与空格相邻的黑色棋子,将它移进空格。

第一个不能按照规则操作的人输掉游戏。为了描述方便,下面将操作“将第x行第y列中的棋子移进空格中”记为M(x,y)。 例如下面是三个游戏的例子。

最近兔兔总是输掉游戏,而且蛋蛋格外嚣张,于是兔兔想请她的好朋友——你——来帮助她。她带来了一局输给蛋蛋的游戏的实录,请你指出这一局游戏中所有她“犯错误”的地方。 注意:

两个格子相邻当且仅当它们有一条公共边。

兔兔的操作是“犯错误”的,当且仅当,在这次操作前兔兔有必胜策略,而这次操作后蛋蛋有必胜策略。

题解

  • 这题显然可以转化成一个二分图模型
  • 在一个二分图中,从给定的起点u开始移动棋子,两个玩家轮流移动,不得经过重复的点,若一方无法移动即为输家
  • 某人必败当且仅当最大匹配中不存在起点u
  • 然后就很容易做了

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 #include <vector>
 5 #define N 2510
 6 using namespace std;
 7 const int dx[4]={0,1,0,-1},dy[4]={1,0,-1,0};
 8 int n,m,k,sx,sy,a[50][50],vis[N],p[N];
 9 vector<int> q[N],ans;
10 bool bz[N],b[N];
11 bool dfs(int x)
12 {
13     if (bz[x]) return 0;
14     for (int i=0;i<q[x].size();i++)
15     {
16         int y=q[x][i];
17         if (!bz[y]&&!vis[y])
18         {
19             vis[y]=1;
20             if (!p[y]||dfs(p[y])) { p[y]=x,p[x]=y; return 1; }
21         }
22     }
23     return 0;
24 }
25 int main()
26 {
27     scanf("%d%d",&n,&m);
28     for (int i=1;i<=n;i++)
29         for (int j=1;j<=m;j++)
30         {
31             char ch=getchar(); while (ch!=‘X‘&&ch!=‘O‘&&ch!=‘.‘) ch=getchar();
32             a[i][j]=(ch==‘O‘)?1:2; if (ch==‘.‘) sx=i,sy=j;
33         }
34     for (int i=1;i<=n;i++)
35         for (int j=1;j<=m;j++)
36             for (int k=0;k<4;k++)
37             {
38                 int xx=i+dx[k],yy=j+dy[k];
39                 if (xx<1||xx>n||yy<1||yy>m) continue;
40                 if (a[i][j]!=a[xx][yy]) q[(i-1)*m+j].push_back((xx-1)*m+yy);
41             }
42     for (int i=1;i<=n;i++) for (int j=1;j<=m;j++) if (a[i][j]==2) memset(vis,0,sizeof(vis)),dfs((i-1)*m+j);
43     scanf("%d",&k);
44     for (int i=1,x,y;i<=k*2;i++)
45     {
46         x=(sx-1)*m+sy,bz[x]=1;
47         if (p[x]) y=p[x],p[x]=p[y]=0,memset(vis,0,sizeof(vis)),b[i]=!dfs(y);
48         scanf("%d%d",&sx,&sy);
49     }
50     for (int i=1;i<=k;i++) if (b[i*2-1]&&b[i*2]) ans.push_back(i);
51     printf("%d\n",ans.size());;
52     for (int i=0;i<ans.size();i++) printf("%d\n",ans[i]);
53 }

原文地址:https://www.cnblogs.com/Comfortable/p/11224751.html

时间: 2024-11-08 22:06:39

[匈牙利算法][博弈] Luogu P1971 兔兔与蛋蛋的相关文章

【博弈+二分图匹配】[NOI2011]兔兔与蛋蛋游戏

题目描述 Description Input 输入的第一行包含两个正整数 n.m. 接下来 n行描述初始棋盘.其中第i 行包含 m个字符,每个字符都是大写英文字母"X".大写英文字母"O"或点号"."之一,分别表示对应的棋盘格中有黑色棋子.有白色棋子和没有棋子.其中点号"."恰好出现一次. 接下来一行包含一个整数 k(1≤k≤1000) ,表示兔兔和蛋蛋各进行了k次操作. 接下来 2k行描述一局游戏的过程.其中第 2i – 1

luogu3386 【模板】二分图匹配 匈牙利算法 hdu2063 过山车 dinic

luogu 匈牙利算法 #include <iostream> #include <cstring> #include <cstdio> using namespace std; int n, m, uu, vv, e, lnk[1005], ans; bool a[1005][1005], vis[1005]; bool dfs(int u){ for(int i=1; i<=m; i++){ if(a[u][i] && !vis[i]){ vi

匈牙利算法自主总结

看原理之前我们先来了解——匈牙利概念 在我们理解概念之后,我们知道这是一个优化时间的算法 至于原理是什么我们现在来讲(以下图片由一只秀逗提供) 首先我们先来放一张男女找伴侣的图 是不是有种鲜花插在牛粪上的感脚 我们看他们相互的连线,所连的线表示男生对某个女生有好感 那么我们男生按编号从小到大来找对象 很显然1——>1      2——>2,但是到3号的时候发现跟一号是情敌 那怎么办呢?我们假设三号抢的过一号那么一号女生让给了三号 还好一号还喜欢二号女生,那么我们把二号女生给一号 但是之前二号男

匈牙利算法

(一)首先明确匈牙利算法是干嘛滴? 匈牙利算法是解决二部图最大匹配问题滴. (二)算法的核心思想:不断寻找增广路径,每找到一条增广路径,就通过异或操作使匹配边数加一,直到找不到增广路径,算法结束. (三)算法的基本步骤: (1)任取二部图G(X,Y)的匹配M,若M饱和X,则停止.若M不能饱和X,则取X的未标记的M非饱和点x.(标记的点表示经过此点不存在增广路)令S={x},T= ?.(T集合中的点表示N(S)中已经加入增广路的点)(当不存非饱和点或者所有非饱和点都被标记,算法结束) (2)若N(

匈牙利算法dfs模板 [二分图][二分图最大匹配]

最近学了二分图最大匹配,bfs模板却死活打不出来?我可能学了假的bfs 于是用到了dfs模板 寻找二分图最大匹配的算法是匈牙利算法 匈牙利算法的主要程序是寻找增广路 寻找增光路是过程是:从一个未经配对的点出发,历经未配边.匹配边.未配边.匹配边.未配边....最终到达一个未配点的过程,只要把路径中的未配边和匹配边的“身份”对调,匹配就加一了.这就是一个寻找增广路的过程,通过不断寻找增广路,可以找到最大的匹配. 1 #include<cstdio> 2 #include<cstring&g

【codevs】1022覆盖(匈牙利算法)

嗯,先上题目描述... 此题接近裸的匈牙利算法,将陆地和其四周是陆地的点连一条边,这样就有了一个无向图. 接着就是从第一个点出发枚举未被标记的点,标记与其对应的另一个点(因为是1*2的长方形). 开了一个四维数组e[x1][y1][x2][y2],若为零代表点(x1,y1)与(x2,y2)不连通. match[x1][y1][1]放与点(x1,y1)配对的另一个点的x,match[x1][y1][2]放与点(x1,y1)配对点的y. 还有就是更改的时候记得双向更改,因为是无向图啊. 然后就跑df

FOJ 2232 匈牙利算法找二分图最大匹配

题目链接 简单理解匈牙利算法 简单理解二分图 尽量让每一个随从击败一个对手且随从全部存活,关键是为每一个随从找对手(递归过程),"腾". #include<iostream> #include<cstdio> #include<cstring> using namespace std; int used[110]; int g[110][110]; //建立随从和对手的对战关系 int ee[110]; int n; struct people{ i

匈牙利算法——S.B.S.

匈牙利算法是由匈牙利数学家Edmonds于1965年提出,因而得名.匈牙利算法是基于Hall定理中充分性证明的思想,它是部图匹配最常见的算法,该算法的核心就是寻找增广路径,它是一种用增广路径求二分图最大匹配的算法. -------等等,看得头大?那么请看下面的版本: 通过数代人的努力,你终于赶上了剩男剩女的大潮,假设你是一位光荣的新世纪媒人,在你的手上有N个剩男,M个剩女,每个人都可能对多名异性有好感(-_-||暂时不考虑特殊的性取向),如果一对男女互有好感,那么你就可以把这一对撮合在一起,现在

UVALive5874 - Social Holidaying-二分图匹配/匈牙利算法

有n个家庭,m个房间,一个房间只能两个家庭住.求最大匹配. 比较标准的二分图问题.先初始化把可能的家庭建边,然后跑一边匈牙利算法. 最后的答案是最大匹配数/2,因为建图时有重复. #include <cstdio> #include <algorithm> #include <cstring> #include <map> using namespace std; const int MAXN = 410; int uN,vN; int g[MAXN][MA