BZOJ1143 CTSC2008 祭祀river 最短路+二分图
题意:求一张图的最大独立点集
题解:先用Floyd把每个点是否连通跑出来,然后拆点做二分图,左边一列,右边一列,如果u v连通,则将左边的u和右边的v相连,由于需要求一个最大的点集使得其中的任意两个点均不连通,所以跑最大独立集=总点数-最大匹配。
#include <queue> #include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #include <iostream> #include <algorithm> using namespace std; const int MAXN=100+2; const int MAXM=3000+2; struct HASH{ int u; HASH *next; HASH(){} HASH(int _u,HASH *_next):u(_u),next(_next){} }*table[2*MAXN],mem[2*MAXM]; int N,M,dx[2*MAXN],dy[2*MAXN],mx[2*MAXN],my[2*MAXN],cnt; bool g[MAXN][MAXN]; queue<int> q; void Insert(int u,int v){ table[u]=&(mem[cnt++]=HASH(v,table[u]));} void Floyd(){ for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) for(int k=1;k<=N;k++) if(g[j][i] && g[i][k]) g[j][k]=1; } bool BFS(){ memset(dx,0,sizeof(dx)); memset(dy,0,sizeof(dy)); for(int i=1;i<=N;i++) if(mx[i]==-1) q.push(i); int x; bool flag=0; while(!q.empty()){ x=q.front(),q.pop(); for(HASH *p=table[x];p;p=p->next) if(!dy[p->u]){ dy[p->u]=dx[x]+1; if(my[p->u]==-1) flag=1; else dx[my[p->u]]=dy[p->u]+1,q.push(my[p->u]); } } return flag; } bool DFS(int x){ for(HASH *p=table[x];p;p=p->next) if(dy[p->u]==dx[x]+1){ dy[p->u]=0; if(my[p->u]==-1 || DFS(my[p->u])){ my[p->u]=x,mx[x]=p->u; return 1; } } return 0; } int Hopcroft_Karp(){ int ret=0; memset(mx,-1,sizeof(mx)); memset(my,-1,sizeof(my)); while(BFS()) for(int i=1;i<=N;i++) if(mx[i]==-1 && DFS(i)) ret++; return ret; } int main(){ scanf("%d %d",&N,&M); for(int i=1,u,v;i<=M;i++){ scanf("%d %d",&u,&v); g[u][v]=1; } Floyd(); for(int i=1;i<=N;i++) for(int j=1;j<=N;j++) if(i!=j && g[i][j]) Insert(i,N+j); printf("%d\n",N-Hopcroft_Karp()); return 0; }