C
来源:互联网 发布:齐天大圣网络大电影 编辑:程序博客网 时间:2024/06/06 20:34
C - Socks
题目链接
题意为:
Arseniy的妈妈要外出m天,给他准备了n只袜子,并且备注好了第几天穿哪两只袜子。但Arseniy发现,如果按照妈妈的备注穿袜子,会有一些天穿不同颜色的袜子,穿出去会被耻笑。于是,他准备了k种颜料,如果袜子颜色不相同,他会涂成相同颜色。他想知道最少改变几只袜子的颜色,穿出去不会被人笑话。
输入:
n, m, k
接下来一行有n个数,代表n个袜子的颜色
接下来有m行,代表每一天需要穿第几只袜子
输出:
the minimum number of socks that should have their colors changed
他需要改变的最少袜子数
#include <stdio.h>#include <string.h>#include <map>#define N 200005using namespace std;map<int, int>tree[N];int f[N]={0};//并查集祖先int cnt[N];//名下的子孙个数int getf(int t)//找祖先{ if (f[t] == t) return t;//祖先就是自己本身 else { f[t] = getf(f[t]);//继续往前找,直到找到祖先 return f[t];//返回祖先 }}void merge(int l, int r)//合并{ int t1, t2; t1 = getf(l);//找祖先 t2 = getf(r); if (t1 != t2)//不是同一个祖先 { f[t2] = t1;//靠左原则,把左边变为右边祖先,即t2的祖先是t1 cnt[t1] += cnt[t2];//把以t2为祖先的数全部加入t1名下 } return ;}int main(){ int n, m, k, i, l, r, vis[N]; int max[N];//同一祖先下颜色相同袜子的最多数 int color[N]; memset(max, 0, sizeof(max)); memset(vis, 0, sizeof(vis)); scanf("%d %d %d", &n, &m, &k); for (i = 1; i<= n; i++) { scanf("%d", &color[i]); f[i] = i; cnt[i] = 1; } for (i = 1; i <= m; i++) { scanf("%d %d", &l, &r); merge(l, r); } for (i = 1; i <= n; i++) { int root = getf(i);//祖先 tree[root][color[i]]++;//同一祖先下的袜子的不同颜色的个数 if (tree[root][color[i]] > max[root]) max[root] = tree[root][color[i]]; } int sum = 0; for (i = 1; i<= n; i++) { int root = getf(i); if (!vis[root]) { vis[root] = 1; sum += cnt[root] - max[root]; } } printf("%d\n", sum); return 0;}
用并查集:将每天有联系的袜子(就是可能在同一天穿的袜子)构成树,然后组成森林,然后在一棵树上染袜子,将所有的袜子染成这个树上颜色
最多的那种颜色,然后累加
例子:
“`sequence
子树1——–>(1【1】,3【1】,5【2】,6【2】,7【3】)
子树2——–>(8【1】,9【1】,10【1】,2【2】,4【2】)
注释:
【】里为袜子颜色
tree[1][1] = 2; //有2个1号颜色的袜子
tree[1][2] = 2; //有2个2号颜色的袜子
tree[1][3] = 1; //有1个3号颜色的袜子
//以1为祖先的子树中袜子的颜色分布
tree[8][1] = 3; //有3个1号颜色的袜子
tree[8][2] = 2; //有2个2号颜色的袜子
tree[8][3] = 0;
//以8为祖先的子树中袜子的颜色分布
max[1] = 2; //代表以1为祖先的子树中,相同颜色袜子的个数最多为2
max[8] = 3; //代表以8为祖先的子树中,相同颜色袜子的个数最多为3
cnt[1] = 5; //以1为祖先的子树有5个孩子
cnt[8] = 5; //以8为祖先的子树有5个孩子