题意:k种颜色,n只袜子,m次的要求两只袜子颜色相同,问最小改变袜子颜色使得两只袜子颜色相同的操作次数
题解:一开始想只用并查集做,最后直接输出入集次数,但是这样做等于将整个颜色集合直接混入另一种。
正解:计算每个联通块中最大颜色重复数,分别用联通块里袜子总数减去最大重复数,最后加起来就是答案。
所以我们可以选择用邻接表与标记数组来做,用(map初始化默认为0,数组存不下)map来储存c[i]出现的次数。
或者可以选择并查集压缩连接,然后递推出mx数组,最后用n减去每个mx[i]的值。
代码1:
#include<bits/stdc++.h>
using namespace std;
const int MAX=2e5+9;
int n,m,k,a[MAX],mx,cnt=0,ans=0,mark[MAX];
map<int,int> mp;
vector<int> g[MAX];
void dfs(int v)
{
mp[a[v]]++,cnt++,mark[v]=1;
mx=max(mp[a[v]],mx);
for (auto u:g[v]) if (!mark[u]) dfs(u);
}
int main()
{
cin>>n>>m>>k;
for (int i=0;i<n;i++) cin>>a[i];
for (int i=0,v,u;i<m;i++) cin>>v>>u,v--,u--,g[v].push_back(u),g[u].push_back(v);
for (int i=0;i<n;i++) if (!mark[i]) mp.clear(),mx=0,cnt=0,dfs(i),ans+=cnt-mx;
cout<<ans;
}
代码2:
#include <bits/stdc++.h>
using namespace std;
const int N=200100;
int n,m,k,x,y,v[N],fa[N],mx[N],ans;
map<int,int> mp[N];
inline int ask(int x)
{
return fa[x]==x?x:fa[x]=ask(fa[x]);
}
int main()
{
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n;++i)
scanf("%d",&v[i]),fa[i]=i;
for(int i=1;i<=m;++i)
scanf("%d%d",&x,&y),fa[ask(x)]=ask(y);
for(int i=1;i<=n;++i)
mx[ask(i)]=max(mx[ask(i)],++mp[ask(i)][v[i]]);
ans=n;
for(int i=1;i<=n;++i)
ans-=mx[i];
printf("%d",ans);
return 0;
}