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.
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.
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.
描述:
给定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;
}