• 二分图最大匹配|UOJ#78|匈牙利算法|边表|Elena


    #78. 二分图最大匹配

    从前一个和谐的班级,有 nlnl 个是男生,有 nrnr 个是女生。编号分别为 1,,nl1,…,nl 和 1,,nr1,…,nr。

    有若干个这样的条件:第 vv 个男生和第 uu 个女生愿意结为配偶。

    请问这个班级里最多产生多少对配偶?

    输入格式

    第一行三个正整数,nl,nr,mnl,nr,m。

    接下来 mm 行,每行两个整数 v,uv,u 表示第 vv 个男生和第 uu 个女生愿意结为配偶。保证 1vnl1≤v≤nl,1unr1≤u≤nr,保证同一个条件不会出现两次。

    输出格式

    第一行一个整数,表示最多产生多少对配偶。

    接下来一行 nlnl 个整数,描述一组最优方案。第 vv 个整数表示 vv 号男生的配偶的编号。如果 vv 号男生没配偶请输出 00。

    样例一

    input

    2 2 3
    1 1
    1 2
    2 1
    
    

    output

    2
    2 1
    
    

    explanation

    11 号男生跟 22 号女生幸福地生活在了一起~

    22 号男生跟 11 号女生幸福地生活在了一起~

    样例二

    input

    2 2 2
    1 1
    2 1
    
    

    output

    1
    1 0
    
    

    explanation

    班上一个女神一个女汉子,两个男生都去追女神。一种最优方案是:

    11 号男生跟 11 号女生幸福地生活在了一起~

    22 号男生孤独终生。= =||

    限制与约定

    1nl,nr5001≤nl,nr≤500,1m2500001≤m≤250000。

    时间限制1s1s

    空间限制256MB


    这个题目实际上就是二分图匹配的模板题。
    --------
    这里请允许我狠狠地吐槽《啊哈!算法》《信息学奥赛一本通》一类的野鸡书。语言很通俗,外表看起来很花俏没错,但错漏百出。《啊哈!算法》里面有相当一部分内容是有严重错误的,dijkstra、最小生成树、邻接表、匈牙利算法部分都有问题,甚至是代码问题,模板让你交上去wa成狗。
    但我不得不说,上面两本书是适合新手的。
    --------
    这里用的是匈牙利算法,题目很老实没什么坑点。
    注意:边表数组要开到500000以上,因为是无向图,要建两条边。
    注意:match[i]存储i的配偶,1-n1是男方;n1+1-n1+n2是女方,结果要输出男方的配偶,也就是结果要输出match[i](1-n1)。
    注意:对每一个点进行增广路时要判断那个点的配偶是否已经确认了,也就是判断match[i]是否为0。
    注意:对每一个点进行增广路前要把用来标记的数组也就是book数组清0,再book[i]=1;意味着i点访问过了。
    注意:输出的时候如果match[i]!=0match[i]要-n1,否则输出0,原因很简单,自己想。

    讲讲dfs的代码。

    bool dfs(int u)//寻找u节点的配偶
    {
      for (int i=head[u]; i; i=edge[i].next) //枚举以u为出点的每一条边
      if (book[edge[i].to]==0) {//如果某个节点还没有访问过
        book[edge[i].to]=1;//标记已访问过
        if (match[edge[i].to]==0||dfs(match[edge[i].to])) {//match[edge[i].to]==0意味着edge[i].to点还没有配偶;如果edge[i].to点有配偶了,就dfs询问edge[i].to点的配偶能不能“让位”去找别的配偶。这里有点小三上位的意思。如果match[edge[i].to]点找到了新的配偶,就会和edge[i].to点离婚,这样子u点就可以和edge[i].to点在一起啦!
          match[edge[i].to]=u;//标记互为配偶
          match[u]=edge[i].to;
          return 1;//找到配偶
        }
      }
      return 0;//没有找到
    }

    我已经详细地解释了匈牙利代码的主要部分。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstdlib> 
     4 #include<cstring>
     5 #include<cmath>
     6 using namespace std;
     7 int read()
     8 {
     9     int x=0,f=1; char c=getchar();
    10     while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
    11     while (c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
    12     return x*f;
    13 }
    14 long long sum;
    15 int num_edge,head[1100],match[1100],u,v,n1,n2,m;
    16 bool book[1100];
    17 struct Edge
    18 {
    19      int next;
    20      int to;
    21 }edge[510000];
    22 void add_edge(int from,int to)
    23 {
    24      edge[++num_edge].next=head[from];
    25      edge[num_edge].to=to;
    26      head[from]=num_edge;
    27 }
    28 bool dfs(int u)
    29 {
    30      for (int i=head[u]; i; i=edge[i].next) 
    31           if (book[edge[i].to]==0) {
    32                book[edge[i].to]=1;
    33                if (match[edge[i].to]==0||dfs(match[edge[i].to])) {
    34                     match[edge[i].to]=u;
    35                     match[u]=edge[i].to;
    36                     return 1;
    37                  }
    38             }
    39      return 0;
    40 }
    41 int main()
    42 {
    43     n1=read(); n2=read(); m=read();
    44      for (int i=1; i<=m; i++) {
    45           u=read(); v=read()+n1;
    46           add_edge(u,v);
    47          add_edge(v,u);
    48      }
    49      for (int i=1; i<=n1+n2; i++) {
    50           for (int j=1; j<=n1+n2; j++) book[j]=0;
    51           book[i]=1;
    52           if (match[i]==0&&dfs(i)) sum++;
    53      }    
    54      printf("%lld
    ",sum);
    55      for (int i=1; i<=n1; i++) 
    56          if (match[i]!=0) printf("%d ",match[i]-n1);
    57          else printf("0 ");
    58     return 0;
    59 }
    二分图最大匹配

    有问题可以直接在评论里面提问,有需要转载的请得到我的允许,否则按侵权处理。


    Elena loves NiroBC forever!
  • 相关阅读:
    Docker
    java 8 特性
    RISC-V: custom instruction and its simulation(转)
    如何在GCC中添加一条RISC-V指令(转)
    The GNU MCU Eclipse RISC-V Embedded GCC build
    Adding custom instruction to RISCV ISA and running it on gem5 and spike(转)
    How to add a custom instruction to the RISC-V GCC tools?(转)
    Adding and using a new instruction
    vuex2
    jq 显示/隐藏 某个模块
  • 原文地址:https://www.cnblogs.com/AlenaNuna/p/7450155.html
Copyright © 2020-2023  润新知