http://acm.hdu.edu.cn/showproblem.php?pid=1281

题意:小希和Gardon在玩一个游戏:对一个N*M的棋盘,在格子里放尽量多的一些国际象棋里面的“车”,并且使得他们不能互相攻击,这当然很简单,但是Gardon限制了只有某些格子才可以放,小希还是很轻松的解决了这个问题(见下图)注意不能放车的地方不影响车的互相攻击。 
所以现在Gardon想让小希来解决一个更难的问题,在保证尽量多的“车”的前提下,棋盘里有些格子是可以避开的,也就是说,不在这些格子上放车,也可以保证尽量多的“车”被放下。但是某些格子若不放子,就无法保证放尽量多的“车”,这样的格子被称做重要点。Gardon想让小希算出有多少个这样的重要点,你能解决这个问题么?
题解:二分图最大匹配。跑最大流.要使每行每列最多一个车。熟悉二分匹配的人肯定就会想到:把x,y分别当作二分图的两一个部分,最大匹配就是要求的最多的车的数量。这样的原因也很好理解。最大匹配中,每个x点,y点最多只有一条边链接(不包含链接源点和汇点),也就是说,去相同的x或者y,最多只有一个点。要问哪些车是不能没有的,只需要枚举每一个车,如果去掉这个车,最大匹配减小,就是所求的重要点。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
#define inf (1<<29)
const int maxn = 1000 , maxm = 100000;
int NV,n,m,k;
int gap[maxn],dis[maxn],pre[maxn],cur[maxn];
struct Edge {
    int v,f,next;
    Edge() {}
    Edge( int _v,int _f,int _next ) : v(_v),f(_f),next(_next){}    
}edge[maxm];
int E,head[maxn];
void init() {
    E=0;
    memset(head,-1,sizeof(head));    
}
void addedge(int u,int v,int f) {
    edge[E]=Edge(v,f,head[u]);
    head[u]=E++;
    edge[E]=Edge(u,0,head[v]);
    head[v]=E++;    
}
int sap(int st , int en) {
    int maxf = 0;
    for(int i=0;i<NV;i++) {
        dis[i] = gap[i] = 0;
        cur[i] = head[i];    
    }    
    int u = pre[st] = st;
    int aug = inf;
    gap[0] = NV;
    while(dis[st] < NV) {
loop:   for(int &i=cur[u];i!=-1;i=edge[i].next) {
            int v = edge[i].v;
            if(edge[i].f && dis[u]==dis[v]+1) {
                aug = aug < edge[i].f?aug:edge[i].f;
                pre[v] = u;
                u = v;
                if(v == en) {
                    maxf += aug;
                    for(u=pre[u];v!=st;v=u,u=pre[u]) {
                        edge[cur[u]].f -= aug;
                        edge[cur[u]^1].f += aug;    
                    }    
                    aug = inf;
                }    
                goto loop;
            }
        }   
        int mindis = NV;
        for(int i=head[u];i!=-1;i=edge[i].next) {
            int v=edge[i].v;
            if(edge[i].f && mindis > dis[v]) {
                cur[u] = i;
                mindis = dis[v];    
            }  
        }
        if( --gap[dis[u]] == 0 ) break;
        gap[ dis[u] = mindis + 1 ] ++;
        u = pre[u];
    }
    return maxf;
}
pair<int,int> kp[10005];
void Build_Graph( int id ) {
    int st = 0;
    int en = n + m + 1;
    init();
    for( int i = 1 ; i <= n ; i++ )
        addedge(st,i,1);
    for( int j = 1 ; j <= m ; j++ )
        addedge(j+n,en,1);
    for( int i = 0 ; i < k ; i++ ) {
        if( i == id ) continue;
        addedge(kp[i].first,kp[i].second+n,1);
    }
}
int main() {
    int cas = 0;
    while( scanf("%d%d%d",&n,&m,&k) != EOF ) {
        int st = 0;
        int en = n + m + 1;
        NV = n+m+2;
        init();
        int a,b;
        for( int i = 0 ; i < k ; i++ ) {
            scanf("%d%d",&kp[i].first,&kp[i].second);
            addedge(kp[i].first,kp[i].second+n,1);
        }
        for( int i = 1 ; i <= n ; i++ )
            addedge(st,i,1);
        for( int j = 1 ; j <= m ; j++ )
            addedge(j+n,en,1);
        int maxflow = sap(st,en);
        int cnt = 0;
        for( int i = 0 ; i < k ; i++ ) {
            Build_Graph(i);
            int cmp = sap(st,en);
            if( cmp != maxflow ) cnt++;
        }
        printf("Board %d have %d important blanks for %d chessmen.\n",++cas,cnt,maxflow);
    }
    return 0;
}

 

 posted on 2013-09-26 23:27  tobec  阅读(297)  评论(0编辑  收藏  举报