题意: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;
}

发表评论

邮箱地址不会被公开。 必填项已用*标注