BZOJ4554
来源:互联网 发布:custom.js插件 编辑:程序博客网 时间:2024/05/16 17:46
原题链接
Description
给出一个
Solution
把每行/每列以硬石头为界划分成若干个部分,如图:
则每个空地都是一个横着的部分和一个竖着的部分的交,每个部分里最多只能有一个炸弹。
于是把每个部分看成图中的一个顶点;若两个部分交于一块空地则连一条边。显然这是一个二分图,因为竖着的部分之间不会有边,横着的部分之间也不会有边。该图中的一组匹配就表示放了一个炸弹在这两个部分的交上,那么答案就是这个二分图的最大匹配数。
最多划分为
nm 个部分,这些部分之间最多有nm 条边。时间复杂度为O(n2m2) 。
Code
//[Tjoi2016&Heoi2016]游戏#include <cstdio>#include <cstring>int const N=3e3;int n,m; char map[N][N];int cnt,row[N][N],col[N][N];bool ed[N][N];int link[N]; bool used[N];bool match(int u){ for(int v=1;v<=cnt;v++) if(ed[u][v]&&!used[v]) { used[v]=true; if(!link[v]||match(link[v])) {link[v]=u; return true;} } return false;}int Hungary(){ int res=0; for(int i=1;i<=cnt;i++) { memset(used,0,sizeof used); if(match(i)) res++; } return res;}int main(){ scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%s",map[i]+1); for(int i=1;i<=n;i++) for(int j1=1;j1<=m;j1++) { if(map[i][j1]=='#'||row[i][j1]) continue; cnt++; for(int j2=j1;j2<=m&&map[i][j2]!='#';j2++) row[i][j2]=cnt; } for(int j=1;j<=m;j++) for(int i1=1;i1<=n;i1++) { if(map[i1][j]=='#'||col[i1][j]) continue; cnt++; for(int i2=i1;i2<=n&&map[i2][j]!='#';i2++) col[i2][j]=cnt; } for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(map[i][j]=='*') ed[row[i][j]][col[i][j]]=true; printf("%d\n",Hungary()); return 0;}
P.S.
HDU1045是这道题的简化版。
阅读全文