• 暑假集训Day6 B(带花树)


    题目链接在这里:B (codeforces.com)

    答案要求两女夹一男的匹配数,很显然不能用一般的二分图匹配去做,但是这既然是个匹配问题,题目是人出出来的,很显然还是需要转化成我们平时做的那种匹配。所以我们考虑把男生拆开拆成两个点,然后跑一般图匹配。最后拿匹配数减去男生人数就是结果。这就是一个带花树问题,我们知道,带花树匹配一定是间隔匹配,所以如果是答案要求的一对匹配,我们带花树会跑出两个(因为我们将男生拆成两个点看),而对于不合法的匹配(同一个男生自己跟自己匹配),那么最后减去男生人数的时候也把这个减掉了,所以结果是正确的。

    后面遇到了匹配问题还是要想经典的二分图匹配和带花树,因为万变不离其宗,所有的匹配问题都是以这两个为出发点的。

      1 #include "bits/stdc++.h"
      2 using namespace std;
      3 const int MAX=505;
      4 int n,m,tot,cnt,fa[MAX];
      5 int head[MAX],nxt[MAX*MAX],adj[MAX*MAX];
      6 int vis[MAX],id[MAX],ff[MAX],mat[MAX],ans;
      7 int q[2000005],st,ed;
      8 char s[MAX];
      9 inline int getfather(int x){return (fa[x]==x?x:fa[x]=getfather(fa[x]));}
     10 inline int read(){
     11     int an=0,x=1;char c=getchar();
     12     while (c<'0' || c>'9') {if (c=='-') x=-1;c=getchar();}
     13     while (c>='0' && c<='9') {an=an*10+c-'0';c=getchar();}
     14     return an*x;
     15 }
     16 inline void addedge(int u,int v){
     17     tot++;
     18     adj[tot]=v;
     19     nxt[tot]=head[u];
     20     head[u]=tot;
     21 }
     22 inline int lca(int x,int y){
     23     cnt++;
     24     while (vis[x]!=cnt){
     25         if (x){
     26             x=getfather(x);
     27             if (vis[x]==cnt) return x;
     28             vis[x]=cnt;
     29             if (mat[x]!=0)
     30                 x=getfather(ff[mat[x]]);
     31             else x=0;
     32         }
     33         swap(x,y);
     34     }
     35     return x;
     36 }
     37 inline void work(int x,int y,int k){
     38     int z;
     39     while (getfather(x)!=k){
     40         ff[x]=y;
     41         z=mat[x];
     42         if (id[z]==1){
     43             id[z]=0;
     44             q[++ed]=z;
     45         }
     46         if (getfather(z)==z) fa[z]=k;
     47         if (getfather(x)==x) fa[x]=k;
     48         y=z;x=ff[y];
     49     }
     50 }
     51 inline bool bfs(int x){
     52     int i,j,u,v;
     53     int la,no,t,z;
     54     for (i=1;i<=n;i++) fa[i]=i;
     55     memset(id,-1,sizeof(id));
     56     st=ed=0;
     57     q[++ed]=x;id[x]=0;
     58     while (st<ed){
     59         u=q[++st];
     60         for (i=head[u];i;i=nxt[i]){
     61             v=adj[i];
     62             if (id[v]==-1){
     63                 ff[v]=u,id[v]=1;
     64                 if (!mat[v]){
     65                     no=v;
     66                     while (no){
     67                         t=ff[no];
     68                         la=mat[t];
     69                         mat[t]=no;mat[no]=t;
     70                         no=la;
     71                     }
     72                     return true;
     73                 }
     74                 id[mat[v]]=0;
     75                 q[++ed]=mat[v];
     76             }
     77             else if (id[v]==0 && getfather(u)!=getfather(v)){
     78                 z=lca(u,v);
     79                 work(u,v,z);work(v,u,z);
     80             }
     81         }
     82     }
     83     return false;
     84 }
     85 int main(){
     86     freopen ("b.in","r",stdin);freopen ("b.out","w",stdout);
     87     int i,j,u,v,cas;
     88     scanf("%d",&cas);
     89     while (cas--){
     90         n=read(),m=read();
     91 //        scanf("%d %d",&n,&m);
     92         ans=tot=cnt=0;
     93         memset(head,0,sizeof(head));
     94         memset(ff,0,sizeof(ff));
     95         memset(vis,0,sizeof(vis));
     96         memset(mat,0,sizeof(mat));
     97         memset(fa,0,sizeof(fa));
     98         int now=n;
     99         for (i=1;i<=n;i++){
    100             scanf("\n%s",s+1);
    101             addedge(i,i+n);
    102             addedge(i+n,i);
    103             for (j=1;j<=m;j++)
    104                 if (s[j]=='1'){
    105                     addedge(i,2*n+j);
    106                     addedge(2*n+j,i);
    107                     addedge(i+n,2*n+j);
    108                     addedge(2*n+j,i+n);
    109                 }
    110         }
    111         n=2*n+m;
    112         for (i=1;i<=n;i++)
    113             if (!mat[i] && bfs(i))
    114                 ans++;
    115         printf("%d\n",ans-now);
    116     }
    117     return 0;
    118 }
  • 相关阅读:
    hdu4841 圆桌问题[STL vector]
    hdu1002 A + B Problem II[大数加法]
    hdu1501 Zipper[简单DP]
    C语言学习之结构体
    C++学习之从C到C++
    一键自动格式化你的代码
    C标准库string.h中几个常用函数的使用详解
    Jlink使用技巧系列教程索引
    Jlink使用技巧之合并烧写文件
    Jlink使用技巧之烧写SPI Flash存储芯片
  • 原文地址:https://www.cnblogs.com/keximeiruguo/p/16472210.html
Copyright © 2020-2023  润新知