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

来源:互联网 发布:数据库第三范式 例子 编辑:程序博客网 时间:2024/06/05 15:00

题目描述

传送门

题解

对于每行每列以#为界限,分成好几个连通块,同一连通块中的点只能选取一个。
位置都只能属于一个连通块。
s->列的连通块 ,容量为1
行的连通块->T ,容量为1
每个空地从他所属的列连通块->行连通块。
然后求最大流即可。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#define N 100003#define inf 1000000000using namespace std;int belongx[53][53],belongy[53][53],point[N],v[N],nxt[N],remain[N];int tot,mp[53][53],last[N],num[N],cur[N],deep[N],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));} 
原创粉丝点击