CodeForces 731C - Socks ( 并查集 + 贪心 )

题意

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\n",ans);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/jinxisui/article/details/80106346