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; }