题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=
题目大意:
类似八皇后问题,但放的都是车,不需要考虑斜线。
图上会有一些墙,墙挡住之后车之间也无法相互攻击。
问最大可以摆放多少辆车,使彼此都无法相互攻击。
思路来源:
http://gzhu-101majia.iteye.com/blog/1152199
解析:
将行或列抽象为点,映射成键值,而将行列之间的交点抽象为边。
举例:
假设3*3的地图,没有墙。
第一列只能与第一行、第二行、第三行中的一行匹配,
则将第一列抽象为一个点C1,第一到第三行分别抽象为一个点R1-R3,
C1向这三个点分别连边,连接时只能取其中一条。
不妨取R2,代表选取了C1-R2这条边,实际意义时代表选取了(2,1)这个点放子。
C1无法与其他点匹配,代表该列不能再放子;同理R2无法与其他点匹配,代表该行不能再放子。
中间有墙时,分多行或多列处理即可。
考虑到只有交叉点会导致连边,就将交叉点对应行的映射点与交叉点对应列的映射点之间连边。
由于列与列之间,行与行之间没有交集,显然是一个二分图。
代码实现:(静态邻接表AC代码)
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#include <map>
#include <vector>
#include <stack>
#include <queue>
const int INF=0x3f3f3f3f;
const int mod=1e9+7;
const int MOD=998244353;
const double eps=1e-7;
typedef long long ll;
#define vi vector<int>
#define si set<int>
#define pii pair<int,int>
#define pi acos(-1.0)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define sci(x) scanf("%d",&(x))
#define scll(x) scanf("%lld",&(x))
#define sclf(x) scanf("%lf",&(x))
#define pri(x) printf("%d",(x))
#define rep(i,j,k) for(int i=j;i<=k;++i)
#define per(i,j,k) for(int i=j;i>=k;--i)
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
int n,cnt,num,head[20],link[20],r[10][10],c[10][10];
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
char maze[10][10];
bool vis[20];
struct edge{int to,next,w;}e[400];
void init()
{
mem(maze,0);
mem(r,-1);
mem(c,-1);
mem(link,-1);
mem(head,-1);
cnt=0;
num=0;
}
void add(int u,int v)
{
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt++;
}
bool dfs(int u)
{
for(int i=head[u];~i;i=e[i].next)
{
int v=e[i].to;
if(!vis[v])
{
vis[v]=1;
if(link[v]==-1||dfs(link[v]))
{
link[v]=u;
return 1;
}
}
}
return 0;
}
int hungary()
{
int res=0;
mem(vis,0);
mem(link,-1);
rep(u,0,num-1)
{
mem(vis,0);
res+=dfs(u);
}
return res/2;
}
int main()
{
int n;
while(~scanf("%d",&n)&&n)
{
init();
rep(i,0,n-1)scanf("%s",maze[i]);
rep(i,0,n-1)
{
rep(j,0,n-1)
{
if(r[i][j]==-1&&maze[i][j]=='.')//找到左起第一个未标记的.
{
while(j<n&&maze[i][j]=='.')
{
r[i][j]=num;//对行映射
j++;
}
num++;
}
}
}
rep(j,0,n-1)
{
rep(i,0,n-1)
{
if(c[i][j]==-1&&maze[i][j]=='.')//考虑到num=0影响结果 故初始化为-1
{
while(i<n&&maze[i][j]=='.')
{
c[i][j]=num;//对列映射
i++;
}
num++;
}
}
}
rep(i,0,n-1)
{
rep(j,0,n-1)
{
add(r[i][j],c[i][j]);//寻找交叉点
add(c[i][j],r[i][j]);//无向图
}
}
printf("%d\n",hungary());
}
return 0;
}