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

原文地址:https://www.cnblogs.com/zhaohongjie/p/14496134.html