题意:
你得到了单词集W,一组N个单词,它们是彼此的相同字母异序词,任何单词中都没有重复的字母。
一组单词S⊆W称为“无交换”,指如果无法通过交换x中的一对字母(不一定相邻)将单词x∈S转换为另一个单词y∈S。
你需要从给定的单词集W中找出最大的无交换集S的大小。
思路:
每一对单词都有着相同的字母但是字母顺序不同,类似与排列,排列具有奇偶性——等于逆序数的奇偶性,交换(任何)两个字母都会改变奇偶性。因此,如果两个词具有相同的奇偶性,它们不能相邻;如果两个词具有不同的奇偶性,它们可能相邻,我们构造一个邻居之间有边的图,一旦我们定义了n 个单词上的二部图结构,最大独立集数就是n − m(其中m 是二部图中的最大匹配数)
一个独立集是一个图中一些两两不相邻的顶点所形成的集合。换句话说它是由顶点组成的集合 S ,使得 S 中任两个顶点之间没有边。等价地,图中的每条边至多有一个端点属于 S
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=505;
int n,l,ans,b[N];
char s[N][30];
bool a[N][N],vis[N];
//find:是否能找到自己的异类
bool find(int x)
{
if (vis[x]) return 0;
vis[x]=1;
for (int i=1;i<=n;i++)
if (a[x][i])//找到邻居
//邻居没在一个集合中 或 邻居能找到自己的异类
if (!b[i] || find(b[i]))
{
//把这个邻居归位自己的异类扔了
b[i]=x;
return 1;
}
return 0;
}
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++) scanf("%s",s[i]+1);
l=strlen(s[1]+1);
//建图(构造一个邻居之间有边的无向图)
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
int p=0;
for (int k=1;k<=l;k++)
if (s[i][k]!=s[j][k]) p++;
//如果两个词不是swap-free的,它们就是邻居,连上边
if (p==2) a[i][j]=1;
}
//互相去find,所以乘2
ans=n*2;
for (int i=1;i<=n;i++)
{
memset(vis, 0, sizeof(vis));
ans-=find(i);
}
printf("%d",ans/2);
return 0;
}
//swap-free:无法通过交换x中的一对字母(不一定相邻)将单词x∈S转换为另一个单词y∈S
//anagram:相同字母异序词