zoukankan      html  css  js  c++  java
  • 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。

  • 相关阅读:
    eri
    elasticsearch集群搜集nginx日志
    linux 常用
    如何清理Docker占用的磁盘空间?
    ubuntu1804 64位 apt源
    postgresql笔记
    web前端——02 body标签中相关标签
    web前端——01 html介绍和head标签
    python数据库——pymysql模块的使用
    MySql数据库——可视化工具Navicat的使用
  • 原文地址:https://www.cnblogs.com/wjyi/p/5594455.html
Copyright © 2011-2022 走看看