[二分图最大匹配必配点] BZOJ 3546 [ONTAK2010]Life of the Party

来源:互联网 发布:mac 照片 相簿 文件夹 编辑:程序博客网 时间:2024/05/23 11:03
%%%dyh

首先求出最大匹配,下面考虑左边点的情况。
我们将匹配中的边从右往左连,不在匹配中的边从左往右连。
这个时候一条增广路成为一条连续的路径。
从每个左边未匹配的点还是遍历,如果被一个左边的点被访问到,说明存在一条增广路,也就是不一定在最大匹配中。
所有没有被访问到的点一定在最大匹配中。

#include<cstdio>    #include<cstdlib>    #include<algorithm>    #include<cstring>    #define cl(x) memset(x,0,sizeof(x))    #define V G[p].v    using namespace std;         inline char nc()    {        static char buf[100000],*p1=buf,*p2=buf;        if (p1==p2) { p2=(p1=buf)+fread(buf,1,100000,stdin); if (p1==p2) return EOF; }        return *p1++;    }         inline void read(int &x){        char c=nc(),b=1;        for (;!(c>='0' && c<='9');c=nc()) if (c=='-') b=-1;        for (x=0;c>='0' && c<='9';x=x*10+c-'0',c=nc()); x*=b;    }         namespace DINIC{        const int N=20005;        const int M=300005;        struct edge{            int u,v,f;            int next;        }G[M];        int head[N],inum=1;        inline void add(int u,int v,int f,int p){            G[p].u=u; G[p].v=v; G[p].f=f; G[p].next=head[u]; head[u]=p;        }        inline void link(int u,int v,int f){            add(u,v,f,++inum); add(v,u,0,++inum);        }        int S,T;        int dis[N];        int Q[N],l,r;        inline bool bfs(){            memset(dis,-1,sizeof(dis)); l=r=-1;            Q[++r]=S; dis[S]=1;            while (l<r){                int u=Q[++l];                for (int p=head[u];p;p=G[p].next)                    if (G[p].f && dis[V]==-1){                        dis[V]=dis[u]+1; Q[++r]=V;                        if (V==T) return 1;                    }            }            return 0;        }        int cur[N];        int dfs(int u,int flow){            if (u==T) return flow;            int used=0,now;            for (int p=cur[u];p;p=G[p].next)            {                cur[u]=p;                if (G[p].f && dis[V]==dis[u]+1)                {                    now=dfs(V,min(flow-used,(int)G[p].f));                    G[p].f-=now,G[p^1].f+=now;                    used+=now; if (flow==used) break;                }            }            if (!used) dis[u]=-1;            return used;        }        int Dinic(){            int ret=0;            while (bfs())                memcpy(cur,head,sizeof(cur)),ret+=dfs(S,1<<30);            return ret;        }    }      const int N=100005;    int n,m,K;  int x[N],y[N];  int left[N],right[N];    inline void Match()  {      using namespace DINIC;      S=n+m+1,T=n+m+2;      for (int i=1;i<=K;i++)          link(x[i],n+y[i],1<<30);      for (int i=1;i<=n;i++)          link(S,i,1);      for (int i=1;i<=m;i++)          link(n+i,T,1);      Dinic();      for (int i=1;i<=K;i++)      {          int p=2*i;          if (G[p^1].f) left[y[i]]=x[i],right[x[i]]=y[i];      }  }    struct edge{      int u,v,next;  }G[N<<3];  int head[N],inum;    inline void add(int u,int v,int p){      G[p].u=u; G[p].v=v; G[p].next=head[u]; head[u]=p;  }    int vst[N<<2];  int boy[N],girl[N];    #define V G[p].v  inline void dfs(int u)  {      if (vst[u]) return;      vst[u]=1;      for (int p=head[u];p;p=G[p].next)          dfs(V);  }    int main()  {       read(n); read(m); read(K);      for (int i=1;i<=K;i++)          read(x[i]),read(y[i]);      Match();      for (int i=1;i<=K;i++)          if (left[y[i]]==x[i])              add(n+y[i],x[i],++inum);          else              add(x[i],n+y[i],++inum);      for (int i=1;i<=n;i++)          if (!right[i])              dfs(i);      for (int i=1;i<=n;i++)          if (!vst[i])              printf("%d\n",i);      cl(vst); cl(head); inum=0;      for (int i=1;i<=K;i++)          if (left[y[i]]!=x[i])              add(n+y[i],x[i],++inum);          else              add(x[i],n+y[i],++inum);      for (int i=1;i<=m;i++)          if (!left[i])              dfs(n+i);      for (int i=1;i<=m;i++)          if (!vst[n+i])              printf("%d\n",i);      return 0;  }  


0 0
原创粉丝点击