BZOJ1191 HNOI2006 超级英雄Hero 二分图

题意:有N个问题和M种解法,每个问题可以用两种解法,每种解法只能用一次,求最多能解决的问题的数量

题解:

二分图裸题,另附二分图的一些性质:

1 最小覆盖: 最小覆盖要求用最少的点(X集合或Y集合的都行)让每条边都至少和其中一个点关联。可以证明:最少的点(即覆盖数)=最大匹配数

2 最小路径覆盖:  用尽量少的不相交简单路径覆盖有向无环图G的所有结点。解决此类问题可以建立一个二分图模型。把所有顶点i拆成两个:X结点集中的i和Y结点集中的i',如果有边i->j,则在二分图中引入边i->j',设二分图最大匹配为m,则结果就是n-m。

3 最大独立集问题:  在N个点的图G中选出m个点,使这m个点两两之间没有边.求m最大值.  如果图G满足二分图条件,则可以用二分图匹配来做.最大独立集点数 = N - 最大匹配数 

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;

const int MAXN=4000+2;
struct HASH{
    int u;
    HASH *next;
    HASH(){}
    HASH(int _u,HASH *_next):u(_u),next(_next){}
}*table[MAXN],mem[MAXN*MAXN];
int N,M,cnt,mark[MAXN];
bool flag[MAXN];

void Insert(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u]));}

bool DFS(int x){
    for(HASH *p=table[x];p;p=p->next)
        if(!flag[p->u]){
            flag[p->u]=1;
            if(mark[p->u]==-1 || DFS(mark[p->u])){
                mark[p->u]=x;
                return 1;
            }
        }
    return 0;
}

int Hungary(){
    int ret=0;
    memset(mark,-1,sizeof(mark));
    for(int i=1;i<=M;i++){
        memset(flag,0,sizeof(flag));
        if(DFS(i)) ret++;
        else break;
    }
    return ret;
}

int main(){
    scanf("%d%d",&N,&M);
    for(int i=1,a,b;i<=M;i++){
        scanf("%d%d",&a,&b);
        Insert(i,M+a+1),Insert(i,M+b+1);
    }
    printf("%d\n",Hungary());

    return 0;
}
View Code

 

posted @ 2017-02-28 22:04  WDZRMPCBIT  阅读(144)  评论(0编辑  收藏  举报