【图论】【二分图匹配】[ZOJ 1002]Fire Net

来源:互联网 发布:p城办事处优化器 编辑:程序博客网 时间:2024/05/20 10:54

这道题目就是对不同的方向的同一行或者列的连通块进行标号,然后对方向不同且相交的连通快连边,最后做一次二分图最大匹配就好了。

#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;}
0 0
原创粉丝点击