• BZOJ1443: [JSOI2009]游戏Game


    $n leq 100$,$m leq 100$的$n*m$地图,现进行一个博弈:后手先选个点放棋子,然后先后手轮流向上下左右某个方向移动棋子一步,不能移到障碍点,一个非障碍点不能走两次。问所有后手能赢的位置。

    可以发现网格图是一个二分图,在移动时好像在二分图的两边反复横跳。可以在二分图这个模型上进行尝试,比如说,求最大匹配,看一下匹配点和非匹配点的情况。

    从匹配点开始:(不如把放棋子那人叫B)

    A如果走了一条匹配边,那B可以随意走一步,这一步一定是非匹配边,然后轮到A:1、如果A又走了一条匹配边,回到刚才情况;2、A没走匹配边,那情况就反转了,因为连走两条非匹配边一定会走到一个匹配点。等等蛤,B为啥一定可以随意走一步?陷入江局。。

    从非匹配点开始:

    A会走一条非匹配边到一个匹配点,然后B只要走最大匹配即可,因为A每一步都只能走非匹配边到另一个匹配点(如果不是匹配点,那他们走过的路就可以增广,不符合最大匹配)。这样A输定。

    也就是说,只要选择不出现在某一个最大匹配的点,就一定赢。

    直接一次最大匹配算法只能求一个最大匹配,没匹配的点一定是答案。但是,只要在最大匹配算法结束后,从S集的点沿着非匹配边-匹配边走到另外的S集点,这些“另外的点”也是答案,因为走过的路径相当于做了一次没损失没收益的增广,依然是最大匹配。同理,T集的点沿着非匹配边-匹配边走到的T集点也是答案。

    我用的Dinic求最大匹配,所以就看S能到达哪些S集点以及哪些T集点能到T即可。

      1 //#include<iostream>
      2 #include<cstring>
      3 #include<cstdlib>
      4 #include<cstdio>
      5 //#include<queue>
      6 //#include<time.h>
      7 //#include<complex>
      8 #include<algorithm>
      9 #include<stdlib.h>
     10 using namespace std;
     11 
     12 int n,m;
     13 #define maxn 10011
     14 #define maxm 100011
     15 
     16 bool vis[111][111]; int col[maxn],id[111][111],tot;
     17 int qx[maxn],qy[maxn],head,tail;
     18 const int dx[]={0,0,1,-1},dy[]={1,-1,0,0};
     19 bool mp[111][111]; char s[111];
     20 void bfs(int sx,int sy)
     21 {
     22     head=0; tail=1; qx[0]=sx; qy[0]=sy;
     23     col[id[sx][sy]]=1; vis[sx][sy]=1;
     24     while (head!=tail)
     25     {
     26         int nx=qx[head],ny=qy[head]; head++;
     27         for (int i=0;i<4;i++)
     28         {
     29             int xx=nx+dx[i],yy=ny+dy[i];
     30             if (xx<1 || xx>n || yy<1 || yy>m || !mp[xx][yy] || vis[xx][yy]) continue;
     31             vis[xx][yy]=1; col[id[xx][yy]]=-col[id[nx][ny]];
     32             qx[tail]=xx; qy[tail]=yy; tail++;
     33         }
     34     }
     35 }
     36 
     37 struct Edge{int from,to,cap,flow,next;};
     38 struct Network
     39 {
     40     Edge edge[maxm]; int first[maxn],le,n;
     41     Network() {le=2;}
     42     void in(int x,int y,int cap) {Edge &e=edge[le]; e.from=x; e.to=y; e.cap=cap; e.flow=0; e.next=first[x]; first[x]=le++;}
     43     void insert(int x,int y,int cap) {in(x,y,cap); in(y,x,0);}
     44     int dis[maxn],s,t,que[maxn],head,tail,cur[maxn];
     45     bool bfs()
     46     {
     47         for (int i=1;i<=n;i++) dis[i]=0x3f3f3f3f; dis[s]=0;
     48         head=0; tail=1; que[0]=s;
     49         while (head!=tail)
     50         {
     51             int now=que[head++];
     52             for (int i=first[now];i;i=edge[i].next)
     53             {
     54                 Edge &e=edge[i];
     55                 if (e.cap>e.flow && dis[e.to]==0x3f3f3f3f)
     56                 {
     57                     dis[e.to]=dis[now]+1;
     58                     que[tail++]=e.to;
     59                 }
     60             }
     61         }
     62         return dis[t]!=0x3f3f3f3f;
     63     }
     64     int dfs(int x,int a)
     65     {
     66         if (x==t || !a) return a;
     67         int flow=0,f;
     68         for (int &i=cur[x];i;i=edge[i].next)
     69         {
     70             Edge &e=edge[i];
     71             if (dis[e.to]==dis[x]+1 && (f=dfs(e.to,min(a,e.cap-e.flow)))>0)
     72             {
     73                 flow+=f; e.flow+=f;
     74                 edge[i^1].flow-=f; a-=f;
     75                 if (!a) return flow;
     76             }
     77         }
     78         return flow;
     79     }
     80     int Dinic(int s,int t)
     81     {
     82         this->s=s; this->t=t;
     83         int ans=0;
     84         while (bfs())
     85         {
     86             for (int i=1;i<=n;i++) cur[i]=first[i];
     87             ans+=dfs(s,0x3f3f3f3f);
     88         }
     89         return ans;
     90     }
     91     bool vis[maxn],v2[maxn];
     92     void solve()
     93     {
     94         head=0; tail=1; que[0]=s;
     95         memset(v2,0,sizeof(v2)); v2[s]=1;
     96         while (head!=tail)
     97         {
     98             int now=que[head++]; if (col[now]==1) vis[now]=1;
     99             for (int i=first[now];i;i=edge[i].next)
    100             {
    101                 Edge &e=edge[i]; if (v2[e.to] || e.to==t || e.cap<=e.flow) continue;
    102                 que[tail++]=e.to,v2[e.to]=1;
    103             }
    104         }
    105         head=0; tail=1; que[0]=t;
    106         memset(v2,0,sizeof(v2)); v2[t]=1;
    107         while (head!=tail)
    108         {
    109             int now=que[head++]; if (col[now]==-1) vis[now]=1;
    110             for (int i=first[now];i;i=edge[i].next)
    111             {
    112                 Edge &e=edge[i]; if (v2[e.to] || e.to==s) continue;
    113                 if (e.cap==e.flow) que[tail++]=e.to,v2[e.to]=1;
    114             }
    115         }
    116     }
    117 }g;
    118 
    119 int main()
    120 {
    121     scanf("%d%d",&n,&m);
    122     for (int i=1;i<=n;i++)
    123     {
    124         scanf("%s",s+1);
    125         for (int j=1;j<=m;j++) mp[i][j]=(s[j]=='.');
    126     }
    127     for (int i=1;i<=n;i++)
    128         for (int j=1;j<=m;j++) if (mp[i][j])
    129             id[i][j]=++tot;
    130     for (int i=1;i<=n;i++)
    131         for (int j=1;j<=m;j++)
    132             if (mp[i][j] && !vis[i][j]) bfs(i,j);
    133     int s=tot+1,t=s+1; g.n=t;
    134     for (int i=1;i<=n;i++)
    135         for (int j=1;j<=m;j++) if (mp[i][j])
    136             for (int k=0;k<4;k+=2)
    137             {
    138                 int xx=i+dx[k],yy=j+dy[k];
    139                 if (xx<1 || xx>n || yy<1 || yy>m || mp[xx][yy]==0) continue;
    140                 if (col[id[i][j]]==1) g.insert(id[i][j],id[xx][yy],1);
    141                 else g.insert(id[xx][yy],id[i][j],1);
    142             }
    143     for (int i=1;i<=n;i++)
    144         for (int j=1;j<=m;j++) if (mp[i][j])
    145         {
    146             if (col[id[i][j]]==1) g.insert(s,id[i][j],1);
    147             else g.insert(id[i][j],t,1);
    148         }
    149     g.Dinic(s,t);
    150     g.solve();
    151     bool flag=0;
    152     for (int i=1;i<=n;i++)
    153         for (int j=1;j<=m;j++)
    154             if (g.vis[id[i][j]])
    155             {
    156                 if (!flag) {flag=1; puts("WIN");}
    157                 printf("%d %d
    ",i,j);
    158             }
    159     if (!flag) puts("LOSE");
    160     return 0;
    161 }
    View Code
  • 相关阅读:
    数据结构 【实验 串的基本操作】
    Ioc容器依赖注入-Spring 源码系列(2)
    定时任务管理中心(dubbo+spring)-我们到底能走多远系列47
    jvm内存增长问题排查简例
    Ioc容器beanDefinition-Spring 源码系列(1)
    SPI机制
    java工厂-积木系列
    java单例-积木系列
    利用spring AOP 和注解实现方法中查cache-我们到底能走多远系列(46)
    java 静态代理-积木系列
  • 原文地址:https://www.cnblogs.com/Blue233333/p/8570449.html
Copyright © 2020-2023  润新知