HDU 1045 Fire Net 二分图匹配 经典建图方法
题目来源:
题意:
找到图中可以安放堡垒并不会互相攻击的位置方案数。(堡垒向4个方向发射子弹,并且墙可以挡下子弹)
题解:
分析:
要达到题目的要求,只要找到可以满足覆盖所有的空白的放置方案即可。那么便可以将题目转变为二分图最大匹配。
主要解题方案:二分图最大匹配+(一行变多行,一列变多列建图方法)
当然,这题数据不大,也可以使用DFS暴力搜一遍过去。
参考资料:百度文库
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
char mp[50][50];
int n;
int row[50][50],col[50][50],r[50],c[50];
int cnt_c,cnt_r;
bool G[50][50];
bool vi[50];
int dfs(int x)
{
for(int i=0;i<cnt_c;i++)
{
if(G[x][i] && !vi[i])
{
vi[i]=1;
if(c[i]==-1||dfs(c[i]))
{
c[i]=x;
r[x]=i;
return 1;
}
}
}
return 0;
}
int match() //匈牙利算法
{
int ans=0;
memset(r,-1,sizeof(r));
memset(c,-1,sizeof(c));
for(int i=0;i<cnt_r;i++)
if(r[i]==-1)
{
memset(vi,0,sizeof(vi));
ans+=dfs(i);
}
return ans;
}
int main()
{
#ifndef ONLINE_JUDGE
// freopen("test.in","r",stdin);
//freopen("test.out","w",stdout);
#endif
while(cin >> n && n)
{
memset(row,-1,sizeof(row));
memset(col,-1,sizeof(col));
cnt_c=cnt_r=0;
for(int i=0;i<n;i++)
cin >> mp[i];
for(int i=0;i<n;i++) //建图过程1
{
for(int j=0;j<n;j++)
{
if(mp[i][j] == '.' && row[i][j]==-1)
{
for(int k=j;mp[i][k]=='.'&& k<n;k++)
row[i][k]=cnt_r;
cnt_r++;
}
if(mp[j][i]=='.' && col[j][i]==-1)
{
for(int k=j;mp[k][i]=='.'&& k<n;k++)
col[k][i]=cnt_c;
cnt_c++;
}
}
}
memset(G,0,sizeof(G));
for(int i=0;i<n;i++) //建图过程2
for(int j=0;j<n;j++)
if(mp[i][j]=='.')
G[row[i][j]][col[i][j]]=1;
cout << match() << endl;
}
return 0;
}