BZOJ1443: [JSOI2009]游戏Game

如果没有不能走的格子的话,和BZOJ2463一样,直接判断是否能二分图匹配

现在有了一些不能走的格子

黑白染色后求出最大匹配

如果是完备匹配,则无论如何后手都能转移到1*2的另一端,故先手必输

否则的话,将棋子放在不是必须点的点上则先手必赢

证明是这样的:

先手先选一个不在最大匹配里面的点,然后对手有两种情况:

一、走一个在最大匹配里的点,然后有了上面考虑错的那种情况,但是不同的是,如果出现了后手最后走某边达到一个非最大匹配中点,就代表出现了一条增广路,显然因为是最大匹配,所以这种情况是不会出现的,所以这种情况先手必胜。

二、走一个不在最大匹配里的点,然后?诶?这是显然的不对啊!直接增广了,连反向弧神马都不用!!!

于是~~~先手必胜。

于是问题转化为了如何求二分图匹配中的非必须点

求这个的话,直接从一个非匹配点dfs到同一边的匹配点就可以了,注意是可以从一个同侧匹配点到另一个同侧匹配点的

一开始算的时候,我在dfs到一个匹配点就直接return了,思路不清晰的锅

应该是记忆化搜索。。。

为什么关于图的题总是要写很久很久呢 不开森

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int n,mm;
 4 #define N 250005
 5 struct Node{
 6   int to,next;
 7 }e[N*6];
 8 char s[505][505];
 9 int tot,head[N],idx[N],idy[N],id[505][505],match[N],m[N],n1,n2,t1,t2,ans;
10 int h[]={-1,0,1,0};
11 int l[]={0,-1,0,1};
12 bool vis[N],v[N],flag;
13 void add(int x,int y){               
14   e[++tot]=(Node){y,head[x]};head[x]=tot;
15   e[++tot]=(Node){x,head[y]};head[y]=tot;
16 }
17 bool dfs(int x){
18   for(int i=head[x];i;i=e[i].next)
19     if(!vis[e[i].to]){
20       vis[e[i].to]=1;
21       if(!match[e[i].to]||dfs(match[e[i].to])){
22         match[e[i].to]=x;m[x]=e[i].to;return 1;
23       }
24     }
25   return 0;
26 }
27 void dfsz(int x){
28   v[x]=1;
29   for(int i=head[x];i;i=e[i].next){
30     if(!v[match[e[i].to]])dfsz(match[e[i].to]);
31   }
32 }
33 void dfsy(int x){
34   v[x]=1;
35   for(int i=head[x];i;i=e[i].next){
36     if(!v[m[e[i].to]])dfsy(m[e[i].to]);
37   }
38 }
39 int main(){
40   scanf("%d%d",&n,&mm);
41   for(int i=1;i<=n;i++){
42     scanf("%s",s[i]+1);
43     for(int j=1;j<=mm;j++)if(s[i][j]!='#')
44       if((i+j)%2==0)n2++;else n1++;
45   }
46   t1=0;t2=n1;
47   for(int i=1;i<=n;i++)
48     for(int j=1;j<=mm;j++)if(s[i][j]!='#'&&(i+j)%2){
49         if(!id[i][j])id[i][j]=++t1,idx[t1]=i,idy[t1]=j;
50         for(int k=0;k<4;k++){
51           int x=i+h[k],y=j+l[k];
52           if(x&&y&&x<=n&&y<=mm&&s[x][y]!='#'){
53             if(!id[x][y])id[x][y]=++t2,idx[t2]=x,idy[t2]=y;
54             add(id[i][j],id[x][y]);
55           }
56       }
57     }
58 
59   for(int i=1;i<=n1;i++){
60     memset(vis,0,sizeof(vis));
61     if(dfs(i))ans++;
62   }
63   if(ans==n1&&ans==n2){puts("LOSE");return 0;}
64 
65   for(int i=1;i<=n1;i++)if(!m[i])dfsz(i);
66   for(int i=n1+1;i<=n1+n2;i++)if(!match[i])dfsy(i);
67  // for(int i=1;i<=t2;i++)cout<<i<<' '<<v[i]<<endl;
68   puts("WIN");
69   for(int i=1;i<=n;i++)
70     for(int j=1;j<=mm;j++)
71       if(v[id[i][j]])printf("%d %d
",i,j);
72   return 0;
73 }
View Code

1443: [JSOI2009]游戏Game

Time Limit: 10 Sec  Memory Limit: 162 MB
Submit: 964  Solved: 431
[Submit][Status][Discuss]

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。

原文地址:https://www.cnblogs.com/wjyi/p/5594455.html