• Code Names(二分图)


    牛客题目链接:https://ac.nowcoder.com/acm/contest/12606/B

    训练赛第一场,这道题看了半天CY想出是二分图,我也把二分图模板写出来套进去,结果样例都没过,再想想就直接把二分图否定了,结果是因为无向图找的最大匹配需要除以2。。。(太离谱了)。

    然后就往图论里的最大团那里去像,一顿T,真的是崩溃,要是坚持一下仔细读一读题可能就能过了,赛后CY直呼可惜(●'◡'●)。

    因为N<=500,所以时间复杂度O(n3)也不会超时。先将输入的字符串用两个循环建立之间是否存在关系,若字符串只有两个字符不同就定义为有关系,可将关系存在二维数组edge里,即第i个数组和第j个数组有关系就edge[i][j]=1,edge[j][i]=1;

    顺带几个定义。

    二分图的最大独立集:选出一些顶点使得这些顶点两两不相邻,则这些点构成的集合称为独立集。找出一个包含顶点数最多的独立集称为最大独立集。

    二分图的最小顶点覆盖:假如选了一个点就相当于覆盖了以它为端点的所有边。最小顶点覆盖就是选择最少的点来覆盖所有的边。

    二分图的最大团:对于一般图来说,团是一个顶点集合,且由该顶点集合诱导的子图是一个完全图,简单说,就是选出一些顶点,这些顶点两两之间都有边。最大团就是使得选出的这个顶点集合最大。对于二分图来说,我们默认为左边的所有点之间都有边,右边的所有顶点之间都有边。那么,实际上,我们是要在左边找到一个顶点子集X,在右边找到一个顶点子集Y,使得X中每个顶点和Y中每个顶点之间都有边。

    最小顶点覆盖 = 二分图的最大匹配

    最大独立集 = 所有顶点数 - 最小顶点覆盖

    二分图的最大团 = 补图的最大独立集(补图:在原图有边,补图就变为无边,否则就是有边,直接反过来)

    (因为原图最大独立集是两两没关系,所以反过来补图的最大顶立集就是两两有关系了)(๑•̀ㅂ•́)و✧

    根据题目要求,需要找出最多的互相无关系的字符串,就相当于找出最大独立集,那么可以采用二分图匈牙利算法求出最大匹配,然后就可以算出最大独立集。

    注意:题目给出的是无向图,所以求出的最大匹配将所有用到的点用了两遍,(1->2连成边,那么2->1也会形成一条边)所以   最小顶点覆盖=最大匹配/2(大坑)

    附上代码:

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 const int N=505;
     4 int edge[N][N],vis[N],cy[N],n;
     5 int path(int u)//匈牙利算法
     6 {
     7     for(int v=1;v<=n;v++)
     8     {
     9         if(edge[u][v]&&!vis[v])//有边且未遍历过
    10         {
    11             vis[v]=1;//标记
    12             if(!cy[v]||path(cy[v]))//找到增广路
    13             {
    14                 cy[v]=u;//匹配
    15                 return 1;
    16             }
    17         }
    18     }
    19     return 0;
    20 }
    21 
    22 int main(void)
    23 {
    24     char s[N][N];
    25     cin>>n;
    26     memset(cy,0,sizeof(cy));
    27     memset(edge,0,sizeof(edge));
    28     for(int i=1;i<=n;i++)
    29         cin>>(s[i]+1);
    30     int len=strlen(s[1]+1);
    31     for(int i=1;i<=n;i++)
    32     {
    33         for(int j=1;j<i;j++)
    34         {
    35             int ans=0;
    36             for(int k=1;k<=len;k++)
    37             {
    38                 if(s[i][k]!=s[j][k])
    39                     ans++;
    40             }
    41             if(ans==2)
    42             {
    43                 edge[i][j]=1;//形成关系
    44                 edge[j][i]=1;
    45             }
    46         }
    47     }
    48     int sum=0;//最大匹配
    49     for(int i=1;i<=n;i++)
    50     {
    51         memset(vis,0,sizeof(vis));
    52         sum+=path(i);
    53     }
    54     cout<<n-sum/2<<endl;
    55     return 0;
    56 }

    转自:https://i.cnblogs.com/posts/edit;postId=14496134

  • 相关阅读:
    Java static修饰符小记
    nginx的使用
    Java 日期时间格式化
    Java Annotation使用详解
    栈的应用-四则运算表达式
    计算机网络——学习笔记
    Python __builtin__模块
    搭建Harbor私有库
    Prometheus k8s方式安装
    Day4_字典循环
  • 原文地址:https://www.cnblogs.com/zhaohongjie/p/14496134.html
Copyright © 2020-2023  润新知