题目:hdoj1045
题意:给出一个图。当中有 . 和 X 两种,. 为通路,X表示墙,在当中放炸弹,然后炸弹不能穿过墙。问你最多在图中能够放多少个炸弹?
分析:这道题目是在上海邀请赛的题目的数据简化版。数据水了,所以有非常多方法,这里讲二分图最大匹配,题目难点在于建图
想到用暴力过。可是事实证明我想多了。
然后又想到多重二分匹配,后来发现没有办法表示图中的行列中墙的阻隔,后来看了别人的建图,瞬间认为高大上。
建图,首先把每一行中的能够放一个炸弹的一块区域标记为同一个数字。数字不反复,然后列做同样的处理,即缩点。
缩点之后原图矩阵中每一个点都对用一个行数字和一个列数字,然后依照这两个数字进行二分匹配,其同样值仅仅取一个,得到的结果就是ans;
注意:每次推断增广的时候首先检查一下当前点有没有匹配。假设匹配就不用搜索,由于有多个值相应一个点,所以...
代码:
#include <cstdio> #include <cstring> #include <string> #include <iostream> #include <algorithm> using namespace std; const int N = 10; #define Del(x,y) memset(x,y,sizeof(x)) char map[N][N]; int path[N][N]; int line[N][N],row[N][N],link[N],vis[N],vlink[N]; int n,cnt_row,cnt_line; bool dfs(int x) { for(int i=0;i<cnt_line;i++) { if(path[x][i]==1 && vis[i]==0) { vis[i]=1; if(link[i]==-1 || dfs(link[i])) { link[i]=x; vlink[x]=i; return true; } } } return false; } void solve() { int ans=0; Del(link,-1); Del(vlink,-1); for(int i=0;i<cnt_row;i++) { if(vlink[i]==-1){ ///注意!标记找过的 Del(vis,0); if(dfs(i)) ans++; } } printf("%d\n",ans); } int main() { //freopen("Input.txt","r",stdin); while(~scanf("%d",&n) && n) { char c; Del(map,0); for(int i=0;i<n;i++) { getchar(); for(int j=0;j<n;j++) scanf("%c",&map[i][j]); } Del(line,-1); Del(row,-1); cnt_row=0,cnt_line=0; for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(map[i][j] == '.' && row[i][j] == -1) { for(int k = j; map[i][k] == '.' && k < n; ++k) row[i][k] = cnt_row; cnt_row++; } if(map[j][i] == '.' && line[j][i] == -1) { for(int k = j; map[k][i] == '.' && k < n; ++k) line[k][i] = cnt_line; cnt_line++; } } } Del(path,0); for(int i=0;i<n;i++) { for(int j=0;j<n;j++) { if(map[i][j]=='.') path[row[i][j]][line[i][j]]=1; } } solve(); } return 0; }