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;
}