zoukankan      html  css  js  c++  java
  • luogu4055 游戏 (二分图博弈)

    考虑对非障碍的点黑白染色然后做二分图最大匹配,那么有结论,先手必胜当且仅当不是完美匹配,而且可以放的点是那些可以不匹配的点

    从非匹配点开始走,后手只能走到匹配点,于是先手就可以走匹配边。由于不能走走过的点,所以现在又变成了一个非匹配点;这样下去直到后手无路可走,所以先手必胜

    反观完美匹配的情况,先手放在任意一个匹配的位置,后手都可以走匹配边从而变成了上面的情况,就是后手必胜

    这类问题大概可以总结为:(一类可以用二分图来描述的博弈问题)

    1.博弈者人数为两人,双方轮流进行决策。
    2.博弈状态(对应点)可分为两类(状态空间可分为两个集合),对应二分图两边(X集和Y集)。任意合法的决策(对应边)使状态从一类跳转到另一类。(正是由于这个性质使得问题可以用二分图描述)
    3.不可以转移至已访问的状态。(不可重复访问点)
    4.无法转移者判负。

     1 #include<bits/stdc++.h>
     2 #define pa pair<int,int>
     3 #define CLR(a,x) memset(a,x,sizeof(a))
     4 #define MP make_pair
     5 #define fi first
     6 #define se second
     7 using namespace std;
     8 typedef long long ll;
     9 typedef unsigned long long ull;
    10 typedef unsigned int ui;
    11 typedef long double ld;
    12 const int maxn=105,maxp=1e4+10;
    13 
    14 inline char gc(){
    15     return getchar();
    16     static const int maxs=1<<16;static char buf[maxs],*p1=buf,*p2=buf;
    17     return p1==p2&&(p2=(p1=buf)+fread(buf,1,maxs,stdin),p1==p2)?EOF:*p1++;
    18 }
    19 inline ll rd(){
    20     ll x=0;char c=gc();bool neg=0;
    21     while(c<'0'||c>'9'){if(c=='-') neg=1;c=gc();}
    22     while(c>='0'&&c<='9') x=(x<<1)+(x<<3)+c-'0',c=gc();
    23     return neg?(~x+1):x;
    24 }
    25 
    26 int N,M,id[maxn][maxn],pct,cnt[2];
    27 char mp[maxn][maxn];
    28 bool col[maxp],flag[maxp],ans[maxp];
    29 int eg[maxp*4][2],egh[maxp],bel[maxp],ect;
    30 
    31 inline void adeg(int a,int b){
    32     eg[++ect][0]=b,eg[ect][1]=egh[a],egh[a]=ect;
    33 }
    34 
    35 bool dfs(int x){
    36     for(int i=egh[x];i;i=eg[i][1]){
    37         int b=eg[i][0];if(flag[b]) continue;
    38         flag[b]=1;
    39         if(!bel[b]||dfs(bel[b])){
    40             bel[b]=x,bel[x]=b;
    41             return 1;
    42         }
    43     }return 0;
    44 }
    45 
    46 int main(){
    47     //freopen("","r",stdin);
    48     N=rd(),M=rd();
    49     for(int i=1;i<=N;i++) scanf("%s",mp[i]+1);
    50     for(int i=1;i<=N;i++){
    51         for(int j=1;j<=M;j++){
    52             if(mp[i][j]=='.'){
    53                 id[i][j]=++pct;
    54                 cnt[col[pct]=(i&1)^(j&1)]++;
    55                 if(i>1&&mp[i-1][j]=='.')
    56                     adeg(id[i-1][j],id[i][j]),adeg(id[i][j],id[i-1][j]);
    57                 if(j>1&&mp[i][j-1]=='.')
    58                     adeg(id[i][j-1],id[i][j]),adeg(id[i][j],id[i][j-1]);
    59             }
    60         }
    61     }
    62     int nn=0;
    63     for(int i=1;i<=pct;i++){
    64         CLR(flag,0);
    65         if(col[i]) nn+=dfs(i);
    66     }
    67     if(nn==cnt[0]&&nn==cnt[1]) puts("LOSE");
    68     else{
    69         puts("WIN");
    70         for(int i=1;i<=pct;i++){
    71             CLR(flag,0);
    72             flag[i]=1;
    73             if(!bel[i]||dfs(bel[i])) bel[i]=0,ans[i]=1;
    74         }
    75         for(int i=1;i<=N;i++){
    76             for(int j=1;j<=M;j++){
    77                 if(ans[id[i][j]]) printf("%d %d
    ",i,j);
    78             }
    79         }
    80     }
    81     return 0;
    82 }
  • 相关阅读:
    通达OA二次开发
    通达OA 工作流程 表单设计 高级应用
    PLSQL Develop PlugIn 之脚本自动匹配补全工具CnPlugin
    Oracle性能优化之SQL语句
    Linux重置root密码步骤
    ORA-03113:通信通道的文件结尾解决
    Bat脚本实现MySQL数据库SQL文件备份
    访问父级组件实例
    访问根实例
    插槽其它示例
  • 原文地址:https://www.cnblogs.com/Ressed/p/10779010.html
Copyright © 2011-2022 走看看