Code Names

Code Names

题意:

如果一个字符串通过交换两个位置可以得到另一个字符串(也就是两个字符串只有两个位置不一样且为交换关系),我们称这两个字符串为替代关系。
现在给出n个字符串,求一个集合,使得集合内的字符串均不是交换关系,且使得这个集合最大

题解:

现在给每个字符串一个编号
如果两个字符串i和j成替代关系,我们就从i到j连一条线
这样将n个字符串互相连线,我们就得到一个图,接下来该怎么办?
我们知道连线的字符串是不能在一个集合里的
我们将左右侧都为n个字符串,根据关系连线,得到下图(紫色线)
在这里插入图片描述
这是个二分图,我们在这个二分图上跑最大二分匹配即可,跑出来的结果m就是不能匹配的数量,最大独立集数就是n − m,
(注意,我们一开始令ans=n*2,让ans减去m,最后除以2是答案)
补充一些关系:
独立集:图中两点不相邻就是图的一个独立集
最大独立集 = n - 最大匹配
最大匹配 = 最小点覆盖
最大独立集 = n - 最小点覆盖
最大团 = 补图的最大独立集
最大独立集 = 补图的最大团

代码:

#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
inline int read(){
    
    
   int s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){
    
    if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();//s=(s<<3)+(s<<1)+(ch^48);
   return s*w;
}
const int maxn=6e2+9;
string a[maxn];
int ans=0;
bool vis[maxn];
int edge[maxn][maxn];
int fa[maxn];
int n;
bool find(int x){
    
    
	if(vis[x])return 0;
	vis[x]=1;
	for(int i=1;i<=n;i++)
	{
    
    
		if(edge[x][i])
		{
    
    
			if(fa[i]==0||find(fa[i]))
			{
    
    
				fa[i]=x;
				return 1;
			}
		}
	} 
	return 0;
}
int main()
{
    
    
	
	cin>>n;
	for(int i=1;i<=n;i++){
    
    
		cin>>a[i];
	}
	int len=a[1].length();
	for(int i=1;i<=n;i++){
    
    
		for(int j=1;j<=n;j++){
    
    
			int num=0;
			for(int k=0;k<len;k++)
			{
    
    
				if(a[i][k]!=a[j][k])num++;
			}
			if(num==2)edge[i][j]=1;
		}
	}
	ans=n*2;
	for(int i=1;i<=n;i++)
	{
    
    
		memset(vis,0,sizeof(vis));
		ans-=find(i); 
	}
	cout<<ans/2;
}

猜你喜欢

转载自blog.csdn.net/qq_35975367/article/details/115284342
今日推荐