这题求一个子集,使得任意2个字符串不能通过一次swap相互得到。
即让任意2个字符串可以通过一次swap得到的字符串连边,即求最小点覆盖。
显然任意图N=500无法求(NP问题)
很容易发现:这是个01要素二分图性质。
即设立一个初始串,一个字符串需要X次变化得到初始串,另一个串通过Y次变化得到初始串。
显然:如果(X&1 ) == (Y&1),则这两个字符串不可能连边。
否则可以连边。
即满足了二分图,一个集合内不能连边。求最大独立集。
等于n-最大匹配
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define ls (o<<1)
#define rs (o<<1|1)
#define pb push_back
const double PI= acos(-1.0);
const int M = 2e5+7;
const int N =500+7;
int head[M],cnt;
void init(){cnt=0,memset(head,0,sizeof(head));}
struct EDGE{int to,nxt,val;}ee[M*2];
void add(int x,int y){ee[++cnt].nxt=head[x],ee[cnt].to=y,head[x]=cnt;}
char s[N][N];
int id[N];//第i个字符串要交换几次得到初始字符串
int vs[N],match[N];
bool dfs(int x)
{
for(int i=head[x];i;i=ee[i].nxt)
{
int y=ee[i].to;
if(vs[y])continue;
vs[y]=1;
if(!match[y]||dfs(match[y]))//标记的始终是有部图节点
{
match[y]=x;
return true;
}
}
return false;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin>>n;
cin>>s[1];
int l=strlen(s[1]);
id[1]=0;
for(int d=2;d<=n;d++)
cin>>s[d];
for(int i=1;i<=n;i++)
for(int j=i+1;j<=n;j++)
{
int tp=0;
for(int k=0;k<l;k++)
{
if(s[i][k]!=s[j][k])
tp++;
}
if(tp==2)add(i,j),add(j,i);
//cout<<i<<"-- "<<j<<endl;;
}
for(int d=2;d<=n;d++)
{
int tp=0;
for(int i=0;i<l;i++)
{
for(int j=0;j<l;j++)
{
if(s[d][j]==s[1][i])
{
if(i!=j)
{
swap(s[d][i],s[d][j]);
tp++;
}
break;
}
}
// cout<<i<<" "<<s[d]<<" "<<tp<<endl;
}
id[d]=tp;
}
int ans=0;
for(int i=1;i<=n;i++)
{
memset(vs,0,sizeof(vs));
if(id[i]&1)
if(dfs(i))ans++;
// cout<<i<<" "<<id[i]<<" "<<ans<<endl;
}
cout<<n-ans<<endl;
return 0;
}