【图论】【二分图匹配】[ZOJ 1002]Fire Net
这道题目就是对不同的方向的同一行或者列的连通块进行标号,然后对方向不同且相交的连通快连边,最后做一次二分图最大匹配就好了。
#include <cstdio>
#include <cstring>
#include <algorithm>
//#include <conio.h>
using namespace std;
const int MAXN = 4;
bool vis[MAXN*MAXN*MAXN];
int Map[MAXN+2][MAXN+2];
int id_v[MAXN+2][MAXN+2];
int id_h[MAXN+2][MAXN+2];
int con[MAXN*MAXN*MAXN];
int idcnt, endcnt;
int n;
const int MAXEN = 16;
const int MAXEM = MAXEN * 2;
struct node{
int v;
node *next;
}Edges[MAXEM*2+10], *adj[MAXEN+10], *ecnt=Edges;
void addedge(int u, int v){
++ecnt;
ecnt->v = v;
ecnt->next = adj[u];
adj[u] = ecnt;
}
bool dfs(int u){
//getch();
for(node *p=adj[u];p;p=p->next){
if(!vis[p->v]){
vis[p->v] = true;
if(!con[p->v] || dfs(con[p->v])){
con[u] = p->v;
con[p->v] = u;
return true;
}
}
}
return false;
}
int work(){
int ret = 0;
for(int i=1;i<=endcnt;i++) if(!con[i]){
memset(vis, 0, sizeof vis);
ret += dfs(i);
}
return ret;
}
bool read(){
char t[20];
scanf("%d", &n);
if(!n) return false;
for(int i=1;i<=n;i++){
scanf("%s", t);
for(int j=0;j<n;j++)
Map[i][j+1] = t[j] == 'X' ? 0 : 1;
}
return true;
}
void prepare(){
idcnt=0;
memset(adj, 0, sizeof adj);
ecnt=Edges;
memset(con, 0, sizeof con);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) if(Map[i][j]){
if(!Map[i][j-1]) idcnt++;
id_h[i][j] = idcnt;
}
}
endcnt = idcnt;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) if(Map[j][i]) {
if(!Map[j-1][i]) idcnt++;
id_v[j][i] = idcnt;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++) if(Map[i][j]){
addedge(id_h[i][j], id_v[i][j]);
addedge(id_v[i][j], id_h[i][j]);
}
}
}
int main(){
while(read()){
prepare();
printf("%d\n", work());
}
return 0;
}