您的位置:首页 > 其它

bzoj 4554: [Tjoi2016&Heoi2016]游戏 (最大流)

2017-06-29 16:54 363 查看

题目描述

传送门

题解

对于每行每列以#为界限,分成好几个连通块,同一连通块中的点只能选取一个。

位置都只能属于一个连通块。

s->列的连通块 ,容量为1

行的连通块->T ,容量为1

每个空地从他所属的列连通块->行连通块。

然后求最大流即可。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define N 100003
#define inf 1000000000
using namespace std;
int belongx[53][53],belongy[53][53],point
,v
,nxt
,remain
;
int tot,mp[53][53],last
,num
,cur
,deep
,n,m,sz;
char s[103];
void add(int x,int y,int z)
{
tot++; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; remain[tot]=z;
tot++; nxt[tot]=point[y]; point[y]=tot; v[tot]=x; remain[tot]=0;
}
int addflow(int s,int t)
{
int ans=inf; int now=t;
while (now!=s) {
ans=min(ans,remain[last[now]]);
now=v[last[now]^1];
}
now=t;
while (now!=s) {
remain[last[now]]-=ans;
remain[last[now]^1]+=ans;
now=v[last[now]^1];
}
return ans;
}
void bfs(int s,int t)
{
for (int i=1;i<=t;i++) deep[i]=t+1;
deep[t]=0;
queue<int> p; p.push(t);
while (!p.empty()){
int now=p.front(); p.pop();
for (int i=point[now];i!=-1;i=nxt[i])
if (deep[v[i]]==t+1&&remain[i^1])
deep[v[i]]=deep[now]+1,p.push(v[i]);
}
}
int isap(int s,int t)
{
int ans=0; int now=s; bfs(s,t);
for (int i=1;i<=t;i++) num[deep[i]]++;
for (int i=1;i<=t;i++) cur[i]=point[i];
while (deep[s]<t) {
if (now==t) {
ans+=addflow(s,t);
now=s;
}
bool pd=false;
for (int i=cur[now];i!=-1;i=nxt[i])
if (remain[i]&&deep[now]==deep[v[i]]+1){
pd=true;
cur[now]=i;
last[v[i]]=i;
now=v[i];
break;
}
if (!pd) {
int minn=t+1;
for (int i=point[now];i!=-1;i=nxt[i])
if (remain[i]) minn=min(minn,deep[v[i]]);
if (!-num[deep[now]]) break;
num[deep[now]=minn+1]++;
cur[now]=point[now];
if (now!=s) now=v[last[now]^1];
}
}
return ans;
}
int main()
{
freopen("a.in","r",stdin);
tot=-1;
memset(point,-1,sizeof(point));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) {
scanf("%s",s+1);
for (int j=1;j<=m;j++) {
if (s[j]=='*') mp[i][j]=1;
if (s[j]=='x') mp[i][j]=2;
if (s[j]=='#') mp[i][j]=3;
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++){
if (j==1||mp[i][j-1]==3) ++sz;
belongx[i][j]=sz;
}
int t=sz;
for (int j=1;j<=m;j++)
for (int i=1;i<=n;i++){
if (i==1||mp[i-1][j]==3) ++sz;
belongy[i][j]=sz;
}
int S=sz+1; int T=sz+2;
for (int i=1;i<=t;i++) add(S,i,1);
for (int j=t+1;j<=sz;j++) add(j,T,1);
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
if(mp[i][j]==1) add(belongx[i][j],belongy[i][j],1);
printf("%d\n",isap(S,T));
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  最大流