D

题目描述

A set of words is called swap free if there is no way to turn any word in the set into any other word in the set by swapping only a single pair of (not necessarily adjacent) letters. 
You are given a set of  n  words that are all anagrams of each other. There are no duplicate letters in any word.  Find the size of the largest swap free subset of the given set. Note that it is possible for the largest swap free subset of the given set to be the set itself. 

输入

The first line of input contains a single integer  n  ( 1 ≤ n ≤ 500 ). 
Each of the next  n  lines contains a single word  w  ( 1 ≤ |w| ≤ 26 ). 
Every word contains only lower-case letters and no duplicate letters. All  n  words are unique, and every word is an anagram of every other word. 

输出

Output a single integer, which is the size of the largest swap free subset. 

样例输入

【样例1】
6 
abc 
acb 
cab 
cba 
bac 
bca 
【样例2】
11 
alerts
alters
artels
estral
laster
ratels
salter
slater
staler
stelar
talers
【样例3】
6 
ates 
east 
eats 
etas 
sate 
teas 

样例输出 

【样例1】
3
【样例2】
8
【样例3】
4 

描述
给定n个字符串,找出它的一个子集,使得其中每一个字符串都不能经过一步变换成为子集中的其他字符串

思路:
二分图最大匹配模板题,先找出所有能一步走到的点构成二分图,找到其中的最大匹配,删去这些最大匹配的其中一边的点,剩余的点数就是子集的最大数量。

代码:

#include <iostream>
#include <cstring>

using namespace std;

const int N = 510, M = N * N;

int h[N], e[M], ne[M], idx;
string s[N];
int n;
bool is_con[N];  // 表示另一半是否考虑过
int match[N];  // 记录这个点的配对点是谁

void add(int a, int b)
{
    e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}

bool dfs(int u)
{
    for (int i = h[u]; i != -1; i = ne[i])
    {
        int j = e[i];
        if (!is_con[j])
        {
            is_con[j] = true;
            if (match[j] == 0 || dfs(match[j]))
            {
                match[j] = u;
                return true;
            }
        }
    }
    
    return false;
}

int main()
{
    memset(h, -1, sizeof h);
    
    cin >> n;
    for (int i = 1; i <= n; i ++ ) cin >> s[i];
    
    for (int i = 1; i <= n; i ++ )
        for (int j = 1; j <= n; j ++ )
        {
            if (j == i) continue;
            int cnt = 0;  // 表示不同对数,是2的话就连一条边
            for (int k = 0; k < s[i].size(); k ++ )
                if (s[i][k] != s[j][k]) cnt ++ ;
                
            if (cnt == 2) add(i, j);
        }
    
    int res = 0;
    for (int i = 1; i <= n; i ++ )
    {
        memset(is_con, false, sizeof is_con);
        if (dfs(i)) res ++ ;  // 匹配上就是找到了一对
    }
    
    cout << n - res / 2 << endl;
    
    return 0;
}
posted on 2021-04-07 15:12  Laurance  阅读(65)  评论(0编辑  收藏  举报