题目
在一个 n ∗ n n*n n∗n( n < = 10 n<=10 n<=10)的正方形中,有墙或者空地,求最多安放多少架机枪使每架机关枪上下左右互不攻击。
分析
首先想到的就是深搜。
代码
#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct line{
bool h[12][12];
};
char a[12][12];
line b;
int i,j,ans,n;
void found(line b,int s){
int i,j,p; bool k=0; line c;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (!b.h[i][j]){
c=b;
c.h[i][j]=1;
for (int p=i+1;p<=n;p++)
if (a[p][j]!='X') c.h[p][j]=1; else break;//下
for (int p=i-1;p>=1;p--)
if (a[p][j]!='X') c.h[p][j]=1; else break;//上
for (int p=j+1;p<=n;p++)
if (a[i][p]!='X') c.h[i][p]=1; else break;//右
for (int p=j-1;p>=1;p--)
if (a[i][p]!='X') c.h[i][p]=1; else break;//左
k=1;
found(c,s+1);
}
if (!k&&s>ans) ans=s;//找到了
}
int main(){
scanf("%d",&n); getchar();
while (n){
memset(b.h,0,sizeof(b.h));
for (int i=1;i<=n;i++){
for (int j=1;j<=n;j++) {
a[i][j]=getchar();
if (a[i][j]=='X') b.h[i][j]=1;
} getchar();
}
ans=0;found(b,0);
printf("%d\n",ans);
scanf("%d",&n); getchar();
}
return 0;
}
#分析
当然,对于(
n
<
=
10
n<=10
n<=10)无能为力,所以我们就想到了匈牙利算法,构建一个二分图。
#代码
#include <iostream>
using namespace std;
struct node{short y,next;}e[2501];
const short d[2]={1,-1}; char map[11][11]; bool cover[51];
short ls[51],link[51],w,v1[11][11],v2[11][11]; int n;
bool check(short x,short y){return !(x<1||y<1||x>n||y>n||map[x][y]=='X');}
void add(short x,short y){e[++w].y=y; e[w].next=ls[x]; ls[x]=w;}
bool find(short x){
short t=ls[x];
while (t){
if (!cover[e[t].y]){
cover[e[t].y]=1;
short q=link[e[t].y];
link[e[t].y]=x;
if (!q||find(q)) return 1;
link[e[t].y]=q;
}
t=e[t].next;
}
return 0;
}
int main(){
ios::sync_with_stdio(0);
cin>>n; short m1=0,ans=0,m2=0;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++) cin>>map[i][j];
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (map[i][j]!='X'){
if (!v1[i][j]){//列
v1[i][j]=++m1;
for (int k=0;k<2;k++){
int step=1;
while (check(i+d[k]*step,j)&&!v1[i+d[k]*step][j]) v1[i+d[k]*step][j]=m1,step++;
}
}
if (!v2[i][j]){//行
v2[i][j]=++m2;
for (int k=0;k<2;k++){
int step=1;
while (check(i,j+d[k]*step)&&!v2[i][j+d[k]*step]) v2[i][j+d[k]*step]=m2,step++;
}
}
}
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
if (v1[i][j]&&v2[i][j]&&map[i][j]!='X') add(v1[i][j],v2[i][j]);//有冲突
for (int i=1;i<=m1;i++) fill(cover,cover+51,0),ans+=find(i);
cout<<ans;
return 0;
}