題意:給你一個圖,圖裡有牆壁和空地,空地可以放置一臺機關槍,機關槍可以朝著四個方向發射,子彈不能穿透牆壁,但是射程無限,機關槍會被損壞如果被另一臺機關槍的子彈打到,問你最多能放置多少臺機關槍;
解題思路:考慮每臺機關槍實際能夠朝行和列兩個方向開火,根據貪心的想法,儘可能不在某行和某列的交點放置,那麼如果我們把行和列分成x,y兩部分,每行中能夠連線的空地當作x的一個頂點,每列中能夠連線的空地當作y的一個頂點,問題轉換為在二分圖中找沒有公共頂點的最大邊集,也就是二分圖最大匹配
程式碼:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
using namespace std;
int n;
char s[][];
int match[];
int visit[];
int gra[][];
int row[][],col[][];
int c,r;
int dfs(int u)
{
for(int i=;i<c;i++)
{
if(gra[u][i]&&visit[i]==)
{
visit[i]=;
if(match[i]==-||dfs(match[i]))
{
match[i]=u;
return ;
}
}
}
return ;
}
int main()
{
while(cin>>n&&n)
{
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
cin>>s[i][j];
c=r=;
memset(row,-,sizeof(row));
memset(col,-,sizeof(col));
memset(match,-,sizeof(match));
memset(visit,,sizeof(visit));
memset(gra,,sizeof(gra));
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
if(s[i][j]=='.'&&row[i][j]==-)//找每行的頂點
{
for(int k=j;k<=n;k++)
if(s[i][k]=='.')
row[i][k]=r;
else//遇到牆壁結束
break;
r++;//頂點+1
}
}
for(int j=;j<=n;j++)
{
if(s[j][i]=='.'&&col[j][i]==-)
{
for(int k=j;k<=n;k++)
if(s[k][i]=='.')
col[k][i]=c;
else
break;
c++;
}
}
}
for(int i=;i<=n;i++)
{
for(int j=;j<=n;j++)
{
gra[row[i][j]][col[i][j]]=;
}
}
int ans=;
for(int i=;i<r;i++)
{
memset(visit,,sizeof(visit));
if(dfs(i))
{
ans++;
}
}
cout<<ans<<endl;
}
}