题目链接:D. Swap Free
题意:给你n个长度相同,包含字母种类相同,每种字母数量相同,让你确定一个字符串集合,集合中的任意一个串不能通过交换任意两个不同的位置变成集合中的另一个串,问你集合最大有多个字符串。
思路:
- 我们对于两个一次操作(交换两个不同位置)不能互相变换的串建边,那么答案就是这个图的最大团。
- 一个图的最大团等于这个图补图的最大独立集,那么我们要建这个图的补图。
- 这个图的补图就是对能够一次操作互相变换的两个串建边。
- 那么现在答案就是这个补图的最大独立集。
- 这个补图一定是一个二分图。
- 二分图的最大独立集等于图中点的个数 - 最大匹配数。
- 所以我们现在可以对这个二分图求一个最大匹配。
#include<bits/stdc++.h>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int N = 510;
int n;
vector<int> ma[N];
char s[N][N];
int from[N], tot;
int use[N];
bool match(int x)
{
int len = ma[x].size();
for(int i = 0; i < len; i++)
{
if(!use[ma[x][i]])
{
use[ma[x][i]] = true;
if(!from[ma[x][i]] || match(from[ma[x][i]]))
{
from[ma[x][i]] = x;
return true;
}
}
}
return false;
}
int hungry()
{
tot = 0;
for(int i = 1; i <= n; i++)
{
memset(use, 0, sizeof(use));
if(match(i)) tot++;
}
return tot;
}
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; i++)
{
scanf("%s", s[i]);
}
int len = strlen(s[1]);
for(int i = 1; i <= n; i++)
{
for(int j = i + 1; j <= n; j++)
{
int flag = 0;
for(int k = 0; k < len; k++)
{
if(s[i][k] != s[j][k]) flag++;
if(flag > 2) break;
}
if(flag == 2)
{
ma[i].push_back(j);
ma[j].push_back(i);
}
}
}
printf("%d\n", n - hungry() / 2);//除二是因为,我们求出来的是所有
return 0;//点的匹配
}