标签:
有暴力搜索和二分图匹配两种解题思路。用dfs搜比较容易,而二分图则是一种更为优化的算法。刚刚接触二分图,发现这种思路很巧妙,以后要多加练习。
下面是dfs求法
#include<iostream>
#include<string.h>
using namespace std;
char map[5][5];
int visitr[5]; //记录横坐标
int visitl[5]; //记录纵坐标
int maxn,mm; //mm是每次搜索的结果,maxn记录最大的
int n;
void dfs(int id)
{
if(id>n*n)
{
if(maxn<mm)
maxn=mm;
return;
}
int r=(id+n-1)/n; //将id转化为坐标
int l=id%n;
if(l==0)
l=n;
if(map[r][l]=='X') //遇到墙时,以后的行列又可以使用了
{
visitr[r]=0;
visitl[l]=0;
}
// 遇到空地有用或不用两种选择
if(map[r][l]!='X'&&visitr[r]==0&&visitl[l]==0) //用
{
visitr[r]=1;
visitl[l]=1;
mm++;
dfs(id+1);
mm--;
visitr[r]=0;
visitl[l]=0;
}
dfs(id+1); //不用
}
int main()
{
while(cin>>n&&n)
{
maxn=0;
mm=0;
for(int i=1; i<=n; i++)
{
for(int j=1; j<=n; j++)
{
cin>>map[i][j];
}
}
memset(visitr,0,sizeof(visitr));
memset(visitl,0,sizeof(visitl));
dfs(1);
cout<<maxn<<endl;
}
}
下面是二分图匹配。可以使用的原因是本题可以将行和列分成两部分,并且需要一个行对应一个列,刚好符合二分图的性质。
//主函数外的部分都是模版
#include<iostream>
#include<string.h>
#include<stdio.h>
using namespace std;
int uN,vN;
int visit[100],use[100];
int g[100][100];
char map[5][5];
int r[5][5];
int l[5][5];
bool dfs(int u)
{
for(int i=1;i<=vN;i++)
{
if(!use[i]&&g[u][i])
{
use[i]=true;
if(visit[i]==-1||dfs(visit[i]))
{
visit[i]=u;
return true;
}
}
}
return false;
}
int hungary()
{
int res=0;
memset(visit,-1,sizeof(visit));
for(int i=1;i<=uN;i++)
{
memset(use,0,sizeof(use));
if(dfs(i))
res++;
}
return res;
}
int main()
{
int i,j,n;
while(cin>>n&&n)
{
memset(l,0,sizeof(l));
memset(r,0,sizeof(r));
memset(g,0,sizeof(g));
//该处以下是缩点部分,需要自己手动写,最终目的得到g[][]
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
{
cin>>map[i][j];
if(map[i][j]=='X')
l[i][j]=r[i][j]=-1;
}
uN=0;vN=0;
for(i=1;i<=n;i++) //合并行
for(j=1;j<=n;j++)
{
if(r[i][j]!=-1&&j<=n)
uN++;
while(r[i][j]!=-1&&j<=n)
{
r[i][j]=uN;
j++;
}
}
for(j=1;j<=n;j++) //和并列
for(i=1;i<=n;i++)
{
if(l[i][j]!=-1&&i<=n)
vN++;
while(l[i][j]!=-1&&i<=n)
{
l[i][j]=vN;
i++;
}
}
for(i=1;i<=n;i++) //得到g[][]
for(j=1;j<=n;j++)
{
if(r[i][j]!=-1)
g[r[i][j]][l[i][j]]=1;
}
printf("%d\n",hungary());
}
return 0;
}
标签:
原文地址:http://blog.csdn.net/iq_it/article/details/51365952