之前看了下二分图博弈,觉得理解了
这道板子题,我居然又困惑了好久!!真想抽自己~
明显看出这是一张二分图,我们用 i + j i+j i+j的奇偶性分类
接下来就可以套二分图博弈的板子了
(注意,下面是把先选择第一步棋子放哪里的人认为是先手,也就是Alice)
Ⅰ . 结 论 一 : \color{Red}Ⅰ.结论一: Ⅰ.结论一:
若 先 手 选 择 的 点 可 能 不 在 最 大 匹 配 中 必 胜 若先手选择的点可能不在最大匹配中必胜 若先手选择的点可能不在最大匹配中必胜
若 先 手 选 择 的 点 一 定 在 最 大 匹 配 中 必 败 若先手选择的点一定在最大匹配中必败 若先手选择的点一定在最大匹配中必败
我写的理论证明,感觉还行
所 以 现 在 知 道 一 个 点 一 定 在 最 大 匹 配 中 , 先 跑 网 络 流 所以现在知道一个点一定在最大匹配中,先跑网络流 所以现在知道一个点一定在最大匹配中,先跑网络流
若 s 到 这 个 点 满 流 且 残 量 网 络 中 不 存 在 s 到 这 个 点 的 路 径 , 一 定 是 必 须 点 若s到这个点满流且残量网络中不存在s到这个点的路径,一定是必须点 若s到这个点满流且残量网络中不存在s到这个点的路径,一定是必须点
此 时 是 必 败 的 , 否 则 必 胜 \color{Red}此时是必败的,否则必胜 此时是必败的,否则必胜
当 然 先 手 选 的 点 可 以 在 二 分 图 左 边 , 也 可 以 在 二 分 图 右 边 当然先手选的点可以在二分图左边,也可以在二分图右边 当然先手选的点可以在二分图左边,也可以在二分图右边
所 以 再 建 图 从 t 向 s 跑 最 大 流 , 相 同 方 式 判 断 。 所以再建图从t向s跑最大流,相同方式判断。 所以再建图从t向s跑最大流,相同方式判断。
#include
using namespace std;
#define id(x,y) (x-1)*m+y
const int maxn=2e5+10;
const int inf=1e9;
int n,m,s,t,yin[maxn];
int dis[maxn];
char a[109][109];
struct edge{
int to,nxt,flow;
}d[maxn]; int head[maxn],cnt=1;
void add(int u,int v,int flow){
d[++cnt]=(edge){v,head[u],flow},head[u]=cnt;
d[++cnt]=(edge){u,head[v],0},head[v]=cnt;
}
bool bfs(int s,int t)
{
memset(dis,0,sizeof(dis));
dis[s]=1;
queueq; q.push( s );
while( !q.empty() )
{
int u=q.front(); q.pop();
for(int i=head[u];i;i=d[i].nxt )
{
int v=d[i].to;
if( d[i].flow&&dis[v]==0 )
{
dis[v]=dis[u]+1;
if( v==t ) return true;
q.push( v );
}
}
}
return false;
}
int dinic(int u,int t,int flow)
{
if( u==t ) return flow;
int res=flow;
for(int i=head[u];i&&res;i=d[i].nxt )
{
int v=d[i].to;
if( dis[v]==dis[u]+1&&d[i].flow)
{
int temp=dinic(v,t,min(res,d[i].flow) );
if( temp==0 ) dis[v]=0;
res-=temp;
d[i].flow-=temp;
d[i^1].flow+=temp;
}
}
return flow-res;
}
typedef pairp;
vectorvec;
int main()
{
cin >> n >> m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
cin >> a[i][j];
s=0,t=n*m+1;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if( a[i][j]=='#' ) continue;
if( (i+j)&1 ) add(s,id(i,j),1);
else add(id(i,j),t,1);
yin[id(i,j)]=cnt-1;
if( i>1&&a[i-1][j]=='.' )
{
if( (i+j)&1 ) add(id(i,j),id(i-1,j),1);
else add(id(i-1,j),id(i,j),1);
}
if( j>1&&a[i][j-1]=='.' )
{
if( (i+j)&1 ) add(id(i,j),id(i,j-1),1);
else add(id(i,j-1),id(i,j),1);
}
}
int ans=0;
while( bfs(s,t) ) ans+=dinic(s,t,inf);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if( a[i][j]=='#' ) continue;
if( (i+j)&1 )
{
if( dis[id(i,j)]==0&&d[yin[id(i,j)]].flow==0 ) continue;//在最大匹配的充要条件
else vec.push_back(p(i,j));//只要有可能不在最大匹配,就可以赢
}
}
for(int i=2;i<=cnt;i+=2)
d[i^1].flow+=d[i].flow,d[i].flow=0;
while( bfs(t,s) ) ans+=dinic(t,s,inf);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
{
if( a[i][j]=='#' ) continue;
if( (i+j)&1 ) continue;
else
{
if( dis[id(i,j)]==0&&d[yin[id(i,j)]+1].flow==0 ) continue;//在最大匹配的充要条件
else vec.push_back(p(i,j));//只要有可能不在最大匹配,就可以赢
}
}
cout << vec.size() << endl;
sort(vec.begin(),vec.end());
for(int i=0;i