标签:
有暴力搜索和二分图匹配两种解题思路。用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