http://acm.hdu.edu.cn/showproblem.php?pid=1045
题意:类似于八皇后,但是如果中间有墙隔开的话,皇后是可以放在一列或一行的。
题解:竖着看,将一列中连在一起的格子看成一个点,这些点就是X集。然后横着看按行缩点,这些点就是Y集。如果一行格子与一列格子相交了,那么这两个点相连。求最大匹配就可以了。
代码:
#include <iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char mp[20][20];
int g[40][40];
int mpr[20][20],mpc[20][20];
int r_num,c_num;
int vis[40],used[40];
bool dfs(int r){
int i;
for(i=1;i<=c_num;i++){
if(!vis[i]&&g[r][i]){
vis[i]=1;
if(used[i]==-1||dfs(used[i])){
used[i]=r;
return true;
}
}
}
return false;
}
int xiongyali(){
memset(used,-1,sizeof(used));
int ans=0,i;
for(i=1;i<=r_num;i++){
memset(vis,0,sizeof(vis));
if(dfs(i))ans++;
}
return ans;
}
int main()
{
int i,j,n;
while(~scanf("%d",&n)){
if(n==0)break;
memset(mpr,0,sizeof(mpr));
memset(mpc,0,sizeof(mpc));
memset(g,0,sizeof(g));
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
cin>>mp[i][j];
if(mp[i][j]=='X'){
mpr[i][j]=-1;
mpc[i][j]=-1;
}
}
}
int tot=0;
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
while(mpc[i][j]==-1&&j<=n){
j++;
}
tot++;
while(mpc[i][j]!=-1&&j<=n){
mpc[i][j]=tot;
c_num=tot;
j++;
}
}
}
tot=0;
for(j=1;j<=n;j++){
for(i=1;i<=n;i++){
while(mpr[i][j]==-1&&i<=n)i++;
tot++;
while(mpr[i][j]!=-1&&i<=n){
mpr[i][j]=tot;
r_num=tot;
i++;
}
}
}
for(i=1;i<=n;i++){
for(j=1;j<=n;j++){
if(mpr[i][j]!=-1&&mpc[i][j]!=-1){
g[mpr[i][j]][mpc[i][j]]=1;
}
}
}
printf("%d\n",xiongyali());
}
//cout << "Hello world!" << endl;
return 0;
}