Description
小AA和小YY得到了《喜羊羊和灰太狼》的电影票,都很想去观看,但是电影票只有一张,于是他们用智力游戏决定胜负,赢得游戏的人可以获得电影票。
在N*M的迷宫中有一个棋子,小AA首先任意选择棋子放置的位置。然后,小YY和小AA轮流将棋子移动到相邻的格子里。游戏的规则规定,在一次游戏中,同一个格子不能进入两次,且不能将棋子移动到某些格子中去。当玩家无法继续移动棋子时,游戏结束,最后一个移动棋子的玩家赢得了游戏。
例如下图所示的迷宫,迷宫中”.”表示棋子可以经过的格子,而”#”表示棋子不可以经过的格子:
.##
...
#.#
若小AA将棋子放置在(1,1),则小 AA 则无论如何都无法赢得游戏。
而若小AA将棋子放置在(3,2)或(2,3),则小AA能够赢得游戏。例如,小AA将棋子放置在(3,2),小YY只能将它移动到(2,2),此时小AA再将棋子移动到(2,3),就赢得了游戏。
小AA和小YY都是绝顶聪明的小朋友,且从不失误。小AA到底能不能赢得这场游戏,从而得到珍贵的电影票呢?
对30%的数据,有1<=n,m<=5
对1000%的数据,有1<=n,m<=100
Solution
容易想到把矩阵黑白染色连边,这样就得到了一个二分图,求一遍最大匹配
对于先手而言,若二分图不存在完美匹配,则放在非匹配点一定是最优的。因为后手的第一步必定走到一个匹配点,先手只需要保证一直沿着匹配边走即可,因为不可能存在非匹配边、匹配边交叉出现的增广路,即先手总是能比后手多走一步(根据最大匹配的定义)
若二分图存在完美匹配,那么先手无论如何放置都会输,具体同理;-P
那么跑一遍网络流求完最大匹配后dfs求出非匹配点,这些都是可行的放置方案
大概就是这样,注意加当前弧优化
如果发现和洛谷某题解撞了的话辣个是我写的呀
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <queue>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
using std:: min;
std:: queue<int> que;
const int INF=0x3f3f3f3f;
const int L=205;
const int N=80005;
const int E=640005;
struct edge{int x,y,w,next;}e[E];
int dis[N],rc[L][L],vis[N],bel[N],chs[N];
int cur[N],ls[N],n,m,edCnt=1;
int dx[4][2]={{-1,0},{1,0},{0,-1},{0,1}};
bool flag=false;
char str[L];
void addEdge(int x,int y,int w) {
e[++edCnt]=(edge){x,y,w,ls[x]}; ls[x]=edCnt;
e[++edCnt]=(edge){y,x,0,ls[y]}; ls[y]=edCnt;
// printf("%d %d %d\n", x,y,w);
}
int get_pos(int x,int y) {return (x-1)*m+y;}
int bfs(int st,int ed) {
while (!que.empty()) que.pop();
que.push(st);
rep(i,st,ed) dis[i]=-1; dis[st]=1;
while (!que.empty()) {
int now=que.front(); que.pop();
for (int i=ls[now];i;i=e[i].next) {
if (e[i].w>0&&dis[e[i].y]==-1) {
dis[e[i].y]=dis[now]+1;
if (e[i].y==ed) return 1;
que.push(e[i].y);
}
}
}
return 0;
}
int find(int now,int ed,int mn) {
if (now==ed||!mn) return mn;
int ret=0;
for (int &i=cur[now];i;i=e[i].next) {
if (e[i].w>0&&dis[now]+1==dis[e[i].y]) {
int d=find(e[i].y,ed,min(mn-ret,e[i].w));
ret+=d; e[i].w-=d; e[i^1].w+=d;
if (ret==mn) break;
}
}
return ret;
}
int dinic(int st,int ed) {
int ret=0;
while (bfs(st,ed)) {
rep(i,st,ed) cur[i]=ls[i];
ret+=find(st,ed,INF);
}
return ret;
}
void dfs(int now,int lim) {
if (vis[now]) return ;
vis[now]=1;
if (bel[now]==lim) {
chs[now]=1;
flag=true;
}
for (int i=ls[now];i;i=e[i].next) {
if (e[i].w==lim) dfs(e[i].y,lim);
}
}
int main(void) {
scanf("%d%d",&n,&m);
rep(i,1,n) {
scanf("%s",str);
rep(j,1,m) if (str[j-1]=='#') rc[i][j]=1;
}
rep(i,1,n) rep(j,1,m) {
int now=get_pos(i,j);
if (((i^j)&1)&&!rc[i][j]) {
bel[now]=1;
addEdge(0,now,1);
rep(k,0,3) {
int p=i+dx[k][0],q=j+dx[k][1];
if (p>0&&p<=n&&q>0&&q<=m&&!rc[p][q]) addEdge(now,get_pos(p,q),1);
}
} else if (!((i^j)&1)&&!rc[i][j]) {
addEdge(now,n*m+1,1);
}
}
int mxFlow=dinic(0,n*m+1);
dfs(0,1); fill(vis,0);
dfs(n*m+1,0);
if (flag) {
puts("WIN");
rep(i,1,n) rep(j,1,m) {
if (chs[get_pos(i,j)]) {
printf("%d %d\n", i,j);
}
}
} else puts("LOSE");
return 0;
}