題目鏈接: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;//點的匹配
}