• HDU5090--Game with Pearls 二分图匹配 (匈牙利算法)


    题意:给N个容器,每个容器里有一定数目的珍珠,现在Jerry开始在管子上面再放一些珍珠,放上的珍珠数必须是K的倍数,可以不放。最后将容器排序,如果可以做到第i个容器上面有i个珍珠,则Jerry胜出,反之Tom胜出。

    思路:数据比较小,所以我是水过的,模拟过程 + 贪心就能过。但正解是二分图匹配,之前没接触过。

    二分图匹配:解释一下第二组样例,k = 2;

    从左向右,每一个能够匹配 i 的(a),就去掉 i 周围其他的边,然后再也去掉a能指向的边,计算一下共有几个能匹配的,如果是n,则Jerry胜,否则Tom胜;

    水过的代码

     1 ///水过的代码
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <cstdlib>
     7 #include <string>
     8 #include <sstream>
     9 #include <algorithm>
    10 #define Max 2147483647
    11 #define INF 0x7fffffff
    12 #define N 90010
    13 #define ll long long
    14 #define mem(a,b) memset(a,b,sizeof(a))
    15 #define repu(i, a, b) for(int i = (a); i < (b); i++)
    16 const double PI=-acos(-1.0);
    17 using namespace std;
    18 int a[N];
    19 int main()
    20 {
    21     int n,T,k;
    22     cin>>T;
    23     while(T--)
    24     {
    25         cin>>n>>k;
    26         repu(i,1,1+n)
    27         cin>>a[i];
    28         sort(a+1,a+1+n);
    29         int ok = -1,i=1;
    30         while(i<=n)
    31         {
    32             if(a[i]>i)
    33             {
    34                 ok = 1;
    35                 break;
    36             }
    37             else if(a[i]<i)
    38             {
    39                 a[i]+=k;
    40                 sort(a+1,a+1+n);
    41                 continue;
    42             }
    43             else
    44                 i++;
    45         }
    46         if(ok==1)
    47             cout<<"Tom
    ";
    48         else
    49             cout<<"Jerry
    ";
    50     }
    51     return 0;
    52 }
    View Code

    带权值的二分图匹配(改编下列某大神的代码):

     1 ///http://acm.hust.edu.cn/vjudge/contest/view.action?cid=82360#problem/B
     2 #include <iostream>
     3 #include <cmath>
     4 #include <cstdio>
     5 #include <cstring>
     6 #include <cstdlib>
     7 #include <string>
     8 #include <sstream>
     9 #include <algorithm>
    10 #define Max 2147483647
    11 #define INF 0x7fffffff
    12 #define N 901
    13 #define ll long long
    14 #define mem(a,b) memset(a,b,sizeof(a))
    15 #define repu(i, a, b) for(int i = (a); i < (b); i++)
    16 using namespace std;
    17 int g[N][N],vis[N],march[N],mat[N];
    18 int n;
    19 struct S
    20 {
    21     int val,v;
    22     bool operator < (const S& s ) const
    23     {
    24         return val > s.val;
    25     }
    26 } p[N];
    27 int dfs( int u )
    28 {
    29     for( int v = 1 ; v <= n ; v++ ) ///考虑所有 Yi 顶点 v
    30     {
    31         if(g[u][v]&&!vis[v]) ///v 与 u 邻接,且没有访问过
    32         {
    33             vis[v] = 1;///如果 v 没有匹配,或者 v 已经匹配了,但从 march[v]出发可以找到一条增广路
    34             if(march[v] == -1 || dfs(march[v])) ///注意如果前一个条件成立,则不会递归调用
    35             {
    36                 march[v] = u; ///把 v 匹配给 u
    37                 return 1; ///找到可增广路
    38             }
    39         }
    40     }
    41     mat[u] = 0;///如果不存在从u出发的增广路
    42     return 0 ;
    43 }
    44 
    45 void MaxMatch( ) ///求二部图最大匹配的匈牙利算法
    46 {
    47     int res = 0; ///所求得的最大匹配
    48     for(int i = 1 ; i <= n ; i++)
    49     {
    50         memset(vis , 0 , sizeof(vis)) ;
    51         int u = p[i].v;///按照排好的权值一个个寻找匹配点
    52         res += dfs(u);
    53     }
    54     ///res是能够匹配的个数
    55     repu(i,1,n+1)
    56     {
    57         int t = march[i];///在dfs中是把v匹配给u,因此需要进一步转化
    58         mat[t] = i;
    59     }
    60     for(int i = 1; i < 1+n; i++)
    61         if(i==1)
    62             printf("%d", mat[i]);
    63         else
    64             printf(" %d", mat[i]);
    65 }
    66 int main()
    67 {
    68     int a,b,m;
    69     scanf("%d",&n);
    70     memset(g,0,sizeof(g));
    71     memset(march,-1,sizeof(march));
    72     memset(mat,0,sizeof(mat));
    73     repu(i,1,1+n)
    74     {
    75         scanf("%d",&a);
    76         p[i].val = a;
    77         p[i].v = i;
    78     }
    79     sort(p+1,p+1+n);///按照权值排序
    80     repu(i,1,1+n)
    81     {
    82         scanf("%d",&m);
    83         repu(j,0,m)
    84         {
    85             scanf("%d",&b);
    86             g[i][b] = 1;
    87         }
    88     }
    89     MaxMatch();
    90     return 0;
    91 }
    View Code

    二分图匹配的代码(某个大神的代码,先留着):

    View Code

    POJ1469是一个裸的二分图匹配,有p个课程,n个学生,求是否能让每个课程都有学生。

     1 ///转自:http://blog.csdn.net/hackbuteer1/article/details/7398008
     2 /*==================================================*
     3 | 二分图匹配(匈牙利算法DFS 实现)
     4 | INIT: g[][]邻接矩阵;
     5 | 优点:实现简洁容易理解,适用于稠密图,DFS找增广路快。
     6 | 找一条增广路的复杂度为O(E),最多找V条增广路,故时间复杂度为O(VE)
     7 ==================================================*/
     8 #include<stdio.h>
     9 #include<memory.h>
    10 bool g[110][310]; ///邻接矩阵,true代表有边相连
    11 bool flag,visit[310];    ///记录V2中的某个点是否被搜索过
    12 int match[310];   ///记录与V2中的点匹配的点的编号
    13 int p,n;   ///二分图中左边、右边集合中顶点的数目
    14 
    15 /// 匈牙利算法
    16 bool dfs(int u)
    17 {
    18     for (int i = 1; i <= n; ++i)
    19     {
    20         if (g[u][i] && !visit[i])   ///如果节点i与u相邻并且未被查找过
    21         {
    22             visit[i] = true;   ///标记i为已查找过
    23             if (match[i] == -1 || dfs(match[i]))   ///如果i未在前一个匹配M中,或者i在匹配M中,但是从与i相邻的节点出发可以有增广路径
    24             {
    25                 match[i] = u;  ///记录查找成功记录,更新匹配M(即“取反”)
    26                 return true;   ///返回查找成功
    27             }
    28         }
    29     }
    30     return false;
    31 }
    32 
    33 int main(void)
    34 {
    35     int i,j,k,t,v,ans;
    36     scanf("%d",&t);
    37     while (t--)
    38     {
    39         scanf("%d %d", &p, &n);
    40         for (i = 1; i <= p; i++)
    41         {
    42             for (j = 1; j <= n; j++)
    43                 g[i][j] = false;
    44         }
    45         for (i = 1; i <= n; i++)
    46             match[i] = -1;
    47         flag = true;
    48         for (i = 1; i <= p; i++)
    49         {
    50             scanf("%d",&k);
    51             if (k == 0)
    52                 flag = false;
    53             while (k--)
    54             {
    55                 scanf("%d",&v);
    56                 g[i][v]  = true;
    57             }
    58         }
    59         if (flag)
    60         {
    61             ans = 0;
    62             for (i = 1; i <= p; i++)
    63             {
    64                 memset(visit,false,sizeof(visit));   ///清空上次搜索时的标记
    65                 if(dfs(i))    ///从节点i尝试扩展
    66                     ans++;
    67             }
    68             if (ans == p)
    69                 puts("YES");
    70             else
    71                 puts("NO");
    72         }
    73         else
    74             puts("NO");
    75     }
    76     return 0;
    77 }
    博客讲得很好,很受益

     

  • 相关阅读:
    phalcon之视图缓存
    Java NIO框架Netty教程(一) – Hello Netty
    setsockopt的作用
    支持向量机通俗导论(理解SVM的三层境地)
    quartz中的corn表达式(转)
    Applet 数字签名技术全然攻略
    SJTU 3001. 二哥的幸运
    OGRE之跳出漫长的编译等待
    VB.NET 数组的定义 动态使用 多维数组
    【Python】用Python的“结巴”模块进行分词
  • 原文地址:https://www.cnblogs.com/ACMERY/p/4467842.html
Copyright © 2020-2023  润新知