[BZOJ2150]部落战争(二分图匹配)
2016-11-10 21:57
441 查看
题目描述
传送门题解
可以发现这道题实际上是一个有向图的最小路径覆盖问题。可以转化为二分图匹配来做。
将每一个点拆成两个点,入点和出点。两个点有边相连时,从起点的出点向终点的入点连边,然后用匈牙利算法求最大匹配。
最小路径覆盖即为点数-最大匹配。
代码
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 105 int n,m,r,c,cnt,ans,a ; char s ; int tot,point[N*N*2],nxt[N*N*10],v[N*N*10]; int belong[N*N*2],vis[N*N*2]; void add(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; } bool find(int x,int k) { for (int i=point[x];i;i=nxt[i]) if (vis[v[i]]!=k) { vis[v[i]]=k; if (!belong[v[i]]||find(belong[v[i]],k)) { belong[v[i]]=x; return true; } } return false; } int main() { scanf("%d%d%d%d\n",&n,&m,&r,&c); for (int i=1;i<=n;++i) { gets(s); for (int j=1;j<=m;++j) if (s[j-1]=='x') a[i][j]=1; else cnt++; } for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) { if (a[i][j]) continue; int x=(i-1)*m+j,y; if (i+r<=n&&j-c>=1&&!a[i+r][j-c]) { y=(i+r-1)*m+j-c; add(x,n*m+y); } if (i+r<=n&&j+c<=m&&!a[i+r][j+c]) { y=(i+r-1)*m+j+c; add(x,n*m+y); } if (i+c<=n&&j-r>=1&&!a[i+c][j-r]) { y=(i+c-1)*m+j-r; add(x,n*m+y); } if (i+c<=n&&j+r<=m&&!a[i+c][j+r]) { y=(i+c-1)*m+j+r; add(x,n*m+y); } } for (int i=1;i<=n*m;++i) if (find(i,i)) ans++; printf("%d\n",cnt-ans); }
手工栈
#include<iostream> #include<cstring> #include<cstdio> using namespace std; #define N 105 int n,m,r,c,cnt,ans,a ; char s ; int tot,point[N*N*2],nxt[N*N*10],v[N*N*10]; int belong[N*N*2],vis[N*N*2]; int cur[N*N*2],stack[N*N*2],flag[N*N*2]; void add(int x,int y) { ++tot; nxt[tot]=point[x]; point[x]=tot; v[tot]=y; } void find(int x,int k) { int top=0;stack[++top]=x; cur[x]=point[x]; while (top) { int x=stack[top]; if (flag[belong[v[cur[x]]]]==k) { belong[v[cur[x]]]=x; flag[x]=k; --top; continue; } while (cur[x]&&vis[v[cur[x]]]==k) cur[x]=nxt[cur[x]]; if (!cur[x]) { --top; continue; } int vt=v[cur[x]]; vis[vt]=k; if (!belong[vt]) { belong[vt]=x; flag[x]=k; --top; continue; } cur[belong[vt]]=point[belong[vt]]; stack[++top]=belong[vt]; } } int main() { scanf("%d%d%d%d\n",&n,&m,&r,&c); for (int i=1;i<=n;++i) { gets(s); for (int j=1;j<=m;++j) if (s[j-1]=='x') a[i][j]=1; else cnt++; } for (int i=1;i<=n;++i) for (int j=1;j<=m;++j) { if (a[i][j]) continue; int x=(i-1)*m+j,y; if (i+r<=n&&j-c>=1&&!a[i+r][j-c]) { y=(i+r-1)*m+j-c; add(x,n*m+y); } if (i+r<=n&&j+c<=m&&!a[i+r][j+c]) { y=(i+r-1)*m+j+c; add(x,n*m+y); } if (i+c<=n&&j-r>=1&&!a[i+c][j-r]) { y=(i+c-1)*m+j-r; add(x,n*m+y); } if (i+c<=n&&j+r<=m&&!a[i+c][j+r]) { y=(i+c-1)*m+j+r; add(x,n*m+y); } } for (int i=1;i<=n*m;++i) { find(i,i); if (flag[i]==i) ++ans; } printf("%d\n",cnt-ans); }
总结
①常见的模型一定要很熟练,准确。相关文章推荐
- [BZOJ]2150: 部落战争 二分图匹配
- BZOJ 2150: 部落战争 [二分图匹配][最小路径覆盖]
- [BZOJ2150]部落战争-二分图匹配
- 【bzoj2150】 部落战争 二分图匹配
- bzoj 2150: 部落战争 最小路径覆盖的做法+证明。
- [bzoj2150] 部落战争(二分图最小边覆盖)
- bzoj2150部落战争 最小路径覆盖
- BZOJ2150: 部落战争
- bzoj 2150: 部落战争 (最小路径覆盖)
- [bzoj2150] 部落战争 二分图
- BZOJ 2150: 部落战争 最大流
- 【BZOJ】2150 部落战争 二分图
- bzoj-2150 部落战争
- bzoj2150 部落战争
- 【BZOJ2150】部落战争 最小流
- BZOJ2150 部落战争 【带上下界最小流】
- BZOJ 2150: 部落战争 二分图最小路径覆盖
- BZOJ 2150 cogs 1861 [国家集训队2011]部落战争
- 【bzoj2150】部落战争 有上下界最小流
- 【最小路径覆盖】【二分图】【最大流】【Dinic】bzoj2150 部落战争