题目:Socks
题意:有n只颜色的袜子,有m天,每天穿l,r俩个编号的袜子,如果袜子的颜色不同,将其中一只染色为同一色,问最少染多少次?
思路:用并查集将每天穿的袜子合并,然后将每个集合中的一些袜子染色成同一颜色最多的袜子的那个颜色,即为最少染的次数
(1)用vector将每个集合的袜子存放起来
(2)遍历vector,用map集合记录集合中同种颜色袜子的个数,(此处不能用数组计数,因为初始化多了会超时!)
(3)将每个集合中的总袜子数-颜色最多袜子数 都累加起来即为最终染色次数!
各种参考。。。自己想不到。。。
代码:
#include <iostream>
#include <cstdio>
#include <vector>
#include <string.h>
#include <map>
using namespace std;
int f[200005],a[200005];
vector<int>num[200005];
//void init(int n){int i;for(i=0;i<=n;i++) f[i] = i;}
int find(int v)
{
if(v != f[v])
f[v] = find(f[v]);
return f[v];
}
void meger(int u,int v)
{
int fu = find(u);
int fv = find(v);
if(fu != fv)
f[fv] = fu;
return;}
int main()
{
int n,m,k,l,r,i,j;
while(scanf("%d%d%d",&n,&m,&k)!=EOF)
{
//init(n);
for(i=1;i<=n;i++)
{
f[i] = i;
scanf("%d",&a[i]);
}
for(i=0;i<m;i++)
{
scanf("%d%d",&l,&r);
meger(l,r);//将同一天穿的袜子合并
}
for(i=1;i<=n;i++)
{
num[find(i)].push_back(a[i]);//找出所有的树
}
int ans = 0;
for(i=1;i<=n;i++)
{
int len = num[i].size(),mmax = 0;
if(len > 1)//大于1树说明是要染色
{
//memset(visit,0,sizeof(visit));
//int visit[200005] = {0};
map<int,int>cot;//开辟map集合用于计数,用visit数组标记计数初始化会超时!
for(j=0;j<len;j++)
{
//visit[num[i][j]]++;
cot[num[i][j]]++;//记录各种颜色袜子的个数
mmax = max(mmax,cot[num[i][j]]);//寻找同一颜色最多的袜子
}
ans += (len - mmax);//每次将剩余的袜子染色成最多的那个颜色即可
}
num[i].clear();//清空ver
}
printf("%d\n",ans);
}
return 0;
}