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)); }
相关文章推荐
- 【BZOJ4554】[Tjoi2016&Heoi2016]游戏 二分图最大匹配
- 【二分图最大匹配】BZOJ4554 [Tjoi2016&Heoi2016]游戏
- 【bzoj4554】[Tjoi2016&Heoi2016]游戏 二分图最大匹配
- [bzoj4554] [Tjoi2016&Heoi2016]游戏
- 【bzoj 4554】【Tjoi2016&Heoi2016】【NOIP2016模拟7.12】游戏
- [BZOJ4554][Tjoi2016&Heoi2016][二分图匹配]游戏
- 【BZOJ】4554 [Tjoi2016&Heoi2016]游戏 二分图
- BZOJ_4554_[Tjoi2016&Heoi2016]游戏_二分图匹配
- BZOJ4554 - [TJOI2016&HEOI2016]游戏
- bzoj 4554: [Tjoi2016&Heoi2016]游戏
- BZOJ 4554: [Tjoi2016&Heoi2016]游戏 二分图匹配
- [BZOJ4554][TJOI2016&HEOI2016]游戏(二分图匹配)
- BZOJ 4554 [Tjoi2016&Heoi2016]游戏 ——二分图
- bzoj4554[Tjoi2016&Heoi2016] 游戏
- [BZOJ4554][TJOI2016&&HEOI2016]游戏(匈牙利)
- 【Tjoi2016&Heoi2016】【BZOJ 4554】【JZOJ 4612】游戏
- BZOJ 4554: [Tjoi2016&Heoi2016]游戏
- BZOJ 4554: [Tjoi2016&Heoi2016]游戏
- 二分图 BZOJ4554 [Tjoi2016&Heoi2016]游戏
- BZOJ 4554: [Tjoi2016&Heoi2016]游戏