ACM学习感悟——摸底赛(并查集)
2015-04-12 23:25
253 查看
Problem Description
娜娜好不容易才回忆起自己是娜娜而不是什么Alice,也回忆起了自己要继续探索这个世界的目标,便偷偷溜出皇宫。娜娜发现这个王国有很多个民族组成,每个民族都有自己的方言,更要命的是这些方面差别还很远,这就导致这个王国的人民交流十分困难。娜娜仔细观察并记录了好久,发现总共有m种不同的语言。突然娜娜发现前面有一群天才在讨论问题,但是奈何语言问题,导致这群人交流非常吃力。不过幸亏的是,这群天才都有一个特殊的能力,只要消耗一个单位的能量即可完全领悟一门新的语言(妈妈再也不用担心我的四六级托福雅思GRE!)。于是娜娜久违的的好奇心又开始冒泡了,娜娜希望你告诉她,如果知道了每个人会的语言,是否能让这群天才两两直接或者间接的交流呢?所谓间接得交流是指经过若干个人的翻译使两个人得到相互表达的信息。如果不能,至少需要多少能量才能实现呢?
Input
多组数据,首先是一个正整数t(t<=20)对于每组数据,首先是两个整数n,m(2<=n<=100,1<=m<=100),分别代表人数以及语言的种类数,语言的编号从1~m。
接下来是n行,每行对这个人进行描述
首先是一个整数k,表示这个人已经会k门语言,接下来是k个整数,分别是这个人掌握的语言编号。(0<=k<=m)
Output
对于每组数据,输出一个整数,表示使得这群人能够互相直接或者间接交流所需要的最少能量。
Sample Input
2 2 2 1 2 0 5 5 1 2 2 2 3 2 3 4 2 4 5 1 5
Sample Output
1 0
Hint
样例1中其中第一个人会第二种语言,而第二个人不会任何语言,所以只需要第二个人也学会第二种语言即可交流,所以能量数为1样例2中有5个人,而且这5个人已经可以相互直接或间接进行交流: 1-2-3-4-5,正好构成一条链。因此不需要继续学习新的语言,能量数为0。
这道题说真的看题解看了好久,好吧。。。可以将人与语言分别看做是一个点,然后根据人与语言之间的关系可以将其画成一个图:
这样可以看出,图内有三个连通块,然后只需要补两个边就可以将其全部连通,所以问题的关键就在于求连通块的个数。怎么求连通块,可以用并查集,在每一次输入语言时,将语言与人合并,这样的话,只需要在最后来探查根的个数计科,有一点需要注意的是,如果所有的人都没有学习语言,那么答案就是人数,这一点需要特判。还有,有一个思想就是把语言映射***数+语言号,那么便可以合并。下面是代码:
///////////////////////////////////////////////////////// // // // // Created by Team 3 // // Copyright (c) 2015年 Team 3. All rights reserved. // ///////////////////////////////////////////////////////// #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <cstdlib> #include <algorithm> #include <cctype> #include <stack> #include <queue> #include <map> #include <string> #include <set> #include <vector> #define INF 0x3f3f3f3f #define cir(i,a,b) for (int i=a;i<=b;i++) #define CIR(j,a,b) for (int j=a;j>=b;j--) #define CLR(x) memset(x,0,sizeof(x)) typedef long long ll; using namespace std; #define maxn 200 int g[maxn]; int par[maxn],vis[maxn]; int np,nl; void init(int n) { for (int i=0;i<=n;i++) { par[i]=i; } } int find(int x) { if (par[x]==x) return x; else return par[x]=find(par[x]); } void unite(int x,int y) { x=find(x);y=find(y); if (x==y) return ; par[x]=y; return; } int main() { // freopen("C:\\Users\\john\\Desktop\\in.txt","r",stdin); int t; cin >> t; while (t--) { int k; cin >> np >> nl; int gg=0; init(np+nl); for (int l=1;l<=np;l++) { int k; cin >> k; for (int i=1;i<=k;i++) { int x; cin >> x; gg=1; unite(l,np+x); } } if (!gg) cout << np << endl; else { set<int> s; for (int i=1;i<=np;i++) { int p=find(i); s.insert(p); } cout << s.size()-1 << endl;; } } return 0; }
相关文章推荐
- ACM学习感悟——FZU2192(并查集)
- ACM学习感悟——POJ3723(kruskal,并查集)
- ACM学习历程—SNNUOJ 1110 传输网络((并查集 && 离线) || (线段树 && 时间戳))(2015陕西省大学生程序设计竞赛D题)
- ACM学习感悟——HDU5092(dp)
- ACM学习感悟——POJ1258(kruskal)
- ACM学习历程—Hihocoder 1291 Building in Sandbox(dfs && 离线 && 并查集)
- ACM学习感悟——POJ1932(图论)
- ACM学习感悟——HUD5090(我也不知道我用的啥= =)
- ACM学习感悟——HDU-命运
- ACM学习感悟——POJ2139(Floyd)
- ACM学习历程—HDU 1272 小希的迷宫(并查集)
- ACM学习感悟——暴力专场F(dp)
- ACM学习感悟——HDU257 HOW TO TYPE
- ACM学习感悟——HDU2844 多重背包
- ACM学习感悟——HDU1505 最大0矩阵
- ACM学习感悟——ACdream字符串专场F(manacher)
- ACM学习感悟——POJ3169(差分约束)
- ACM 学习感悟——HDU2845
- ACM 学习之 并查集
- ACM学习感悟——暴力专场E 暴力dp