Code Names(二部图最大匹配问题)

Code Names

题意:

你得到了单词集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:相同字母异序词
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值