Description
Input
输入数据首先输入两个整数N,M,表示了迷宫的边长。 接下来N行,每行M个字符,描述了迷宫。
Output
若小AA能够赢得游戏,则输出一行”WIN”,然后输出所有可以赢得游戏的起始位置,按行优先顺序输出 每行一个,否则输出一行”LOSE”(不包含引号)。
Sample Input
3 3
.##
…
#.#
Sample Output
WIN
2 3
3 2
HINT
对于100%的数据,有1≤n,m≤100。 对于30%的数据,有1≤n,m≤5。
分析
首先考虑黑白染色,那么这就变成了一个二分图,然后求出这个二分图的最大匹配。
假设先手选择了一个非匹配点,那么后手就只能走匹配点,然后先手沿着匹配走。若某一次后手走到了一个非匹配点,那么就出现了一条增广路,与最大匹配矛盾,故先手必胜。
但是如果所有的点都最大匹配了呢?随便先手去选哪个点,后手都可以沿其匹配走,然后先手如果走,又是一个新的最大匹配中点,后手又走其匹配,然后后手就赢了。
那么我们就要考虑如何求出每个非匹配点。
跑一波网络流,我们dfs一遍,看从源点能到哪些染色时归到S集的点;
再dfs一遍,看从哪些染色时归到T集的点能到汇点。
这些点就是答案!(注意建边时需要为有向边!就是反向弧初始流量为0!)
为什么呢?
首先非匹配点肯定是会被扫到的,
然后是匹配点中的可行点:
我们将如何扫到这些可行点呢?
以S集点为例,我们会先扫到一个可行点,然后扫到一个T集点,然后再通过已经有流量的反向弧回到一个匹配点,这样这个匹配点就是可行的了!
代码
#include <bits/stdc++.h>
#define N 105
#define INF 0x7fffff
struct NOTE
{
int to,next,c;
}e[N*N*10];
int last[N*N];
int cnt;
void add(int x,int y,int c)
{
e[++cnt].to = y;
e[cnt].c = c;
e[cnt].next = last[x];
last[x] = cnt;
e[++cnt].to = x;
e[cnt].c = 0;
e[cnt].next = last[y];
last[y] = cnt;
}
int map[N][N];
int n,m,s,t;
int ans;
int pos(int x,int y)
{
return (x - 1) * m + y;
}
int dis[N*N];
int cur[N*N];
bool bfs()
{
for (int i = s; i <= t; i++)
dis[i] = 0;
dis[s] = 1;
std::queue<int> Q;
Q.push(s);
while (!Q.empty())
{
int u = Q.front();
Q.pop();
for (int i = last[u]; i; i = e[i].next)
if (e[i].c && !dis[e[i].to])
{
dis[e[i].to] = dis[u] + 1;
if (e[i].to == t)
return 1;
Q.push(e[i].to);
}
}
return 0;
}
int dfs(int x,int maxf)
{
if (x == t || !maxf)
return maxf;
int ret = 0;
for (int &i = cur[x]; i; i = e[i].next)
if (e[i].c && dis[e[i].to] == dis[x] + 1)
{
int f = dfs(e[i].to,std::min(e[i].c,maxf - ret));
ret += f;
e[i].c -= f;
e[i^1].c += f;
if (ret == maxf)
break;
}
return ret;
}
void dinic()
{
while (bfs())
{
for (int i = s; i <= t; i++)
cur[i] = last[i];
ans += dfs(s,INF);
}
}
int bel[N*N],vis[N*N],cho[N*N];
int dx[4]={1,0,-1,0},dy[4]={0,1,0,-1};
bool flag;
void dfs1(int x,int d)
{
vis[x] = 1;
if (bel[x] == d)
{
cho[x] = 1;
flag = 1;
}
for (int i = last[x]; i; i = e[i].next)
{
if (!vis[e[i].to] && e[i].c == d)
dfs1(e[i].to,d);
}
}
int main()
{
scanf("%d%d",&n,&m);
char ch[N];
for (int i = 1; i <= n; i++)
{
scanf("%s",ch);
for (int j = 0; j < m; j++)
if (ch[j] == '#')
map[i][j + 1] = 1;
}
cnt = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (i % 2 == j % 2 && !map[i][j])
for (int k = 0; k < 4; k++)
{
int x = i + dx[k];
int y = j + dy[k];
if (x < 1 || x > n || y < 1 || y > m || map[x][y])
continue;
add(pos(i,j),pos(x,y),1);
}
s = 0;
t = n * m + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (!map[i][j])
{
if (i % 2 == j % 2)
{
add(s,pos(i,j),1);
bel[pos(i,j)] = 1;
}
else add(pos(i,j),t,1);
}
}
dinic();
dfs1(s,1);
memset(vis,0,sizeof(vis));
dfs1(t,0);
if (flag)
printf("WIN\n");
else printf("LOSE\n");
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
if (cho[pos(i,j)])
printf("%d %d\n",i,j);
}