题意
Arseniy的所有袜子按照1-n编号, 每个袜子的颜色标记为c[i], 现在给出n个袜子和m天的穿袜子方案, 至多有k种颜色( 感觉是无用条件 ), 现在要求她每天穿着方案的两只袜子同色, Arseniy可以将其涂色改变颜色, 求最少的涂色数量
思路
比较容易想到并查集
将每天穿着方案中的两只袜子合并到同一个根节点下, 同一个集合中的袜子必须涂成同一种颜色, 这里用非常简单的贪心思想, 肯定是要将出现颜色次数最多的颜色保留, 剩下的涂色涂成这个颜色
之前T在test47上, 才发现并查集的_find()函数写的有点问题, 应该利用 _find()函数更新父节点
正确的_find() 函数 :
int _find(int a){
if( f[a] != a )
f[a] = _find(f[a]);
return f[a];
}
AC代码
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;
const int maxn = 200000+5;
int c[maxn], f[maxn];
map<int, int> mp[maxn];
int n;
int _find(int a){
if( f[a] != a )
f[a] = _find(f[a]);
return f[a];
}
void _union(int a, int b){
int aa = _find(a), bb = _find(b);
if( aa != bb ) f[bb] = aa;
return;
}
int main()
{
int m, k;
int a, b, mmax, all, ans;
scanf("%d%d%d",&n, &m, &k);
for( int i = 1; i <= n; i++ ){
scanf("%d",&c[i]);
f[i] = i;
}
while(m--){
scanf("%d%d", &a, &b);
_union(a, b);
}
for( int i = 1; i <= n; i++ )
mp[_find(i)][c[i]]++;
ans = 0;
map<int, int>::iterator it;
for( int i = 1; i <= n; i++ ){
it = mp[i].begin();
mmax = 0;
all = 0;
for( ; it != mp[i].end(); it++ ){
all += it->second;
mmax = max(mmax, it->second);
}
ans += (all-mmax);
}
printf("%d
",ans);
return 0;
}