1. 程式人生 > >【二分圖匹配】HDU

【二分圖匹配】HDU

題意:

給出一張圖,‘X’代表牆,‘.’ 代表空地。在空地上放一些炮塔,炮塔不能處在同一行同一列,除非被牆隔開。問最多能放多少個炮塔。

題解:

這題其實可以二進位制暴力模擬去做,但也可以用二分圖來做。

考慮不存在牆的情況,那麼可以把行和列當作兩邊的點,中間放炮塔當作邊,進行二分圖匹配即可。

如果存在牆,牆的兩側其實就相當於是兩個互不相關的點。而對於一連串的空地(即中間不存在牆),由於只能放一個炮臺的特性,所以相當於一個點。

那麼就首先從列出發,對每一列空地縮點並染色。然後從行出發去縮點,並與所染色的對應列連邊。最後進行二分圖匹配即可。

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+7;
struct Edge{
    int u,v,w,nxt;
    Edge(int u=0,int v=0,int w=0,int nxt=0):u(u),v(v),w(w),nxt(nxt){}
}e[N*2];
int p[N],edn;
void add(int u,int v,int w){
    e[++edn]=Edge(u,v,w,p[u]);p[u]=edn;
    e[++edn]=Edge(v,u,w,p[v]);p[v]=edn;
}
int match[N],vis[N];
int n,m;
bool dfs(int u){
    for(int i=p[u];~i;i=e[i].nxt){
        int v=e[i].v;
        if(vis[v]) continue;
        vis[v]=1;
        if(match[v]==-1||dfs(match[v])){
            match[v]=u;
            return true;
        }
    }
    return false;
}
char mp[N][N],col[N][N];
int main()
{
    int n;
    while(scanf("%d",&n)!=EOF){
        if(n==0) break;
        memset(match,-1,sizeof(match));
        memset(p,-1,sizeof(p));edn=-1;
        for(int i=1;i<=n;i++)
            scanf("%s",mp[i]+1);
        int top=1;
        for(int j=1;j<=n;j++){
            for(int i=1;i<=n;i++){
                if(mp[i][j]=='X') top++;
                else col[i][j]=top;
            }
            top++;
        }
        top=1;
        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                if(mp[i][j]=='X') top++;
                else add(top,col[i][j]+100,1);
            }
            top++;
        }
        int ans=0;
        for(int i=1;i<=top;i++){
            memset(vis,0,sizeof(vis));
            if(dfs(i)) ans++;
        }
        printf("%d\n",ans);
    }
    return 0;
}