1920年的芝加哥,出现了一群强盗。如果两个强盗遇上了,那么他们要么是朋友,要么是敌人。而且有一点是肯定的,就是:
我朋友的朋友是我的朋友;
我敌人的敌人也是我的朋友。
两个强盗是同一团伙的条件是当且仅当他们是朋友。现在给你一些关于强盗们的信息,问你最多有多少个强盗团伙。
输入格式:
输入文件gangs.in的第一行是一个整数N(2<=N<=1000),表示强盗的个数(从1编号到N)。 第二行M(1<=M<=5000),表示关于强盗的信息条数。 以下M行,每行可能是F p q或是E p q(1<=p q<=N),F表示p和q是朋友,E表示p和q是敌人。输入数据保证不会产生信息的矛盾。
输出格式:
输出文件gangs.out只有一行,表示最大可能的团伙数。
输出样例#1: 3
先说一下思路:
对于只有朋友信息的数据就不用说了。对于敌人的信息,我们可以给每一个人i设置一个敌人集合E[i],当输入i和j时,我们就把i和E[j]合并,把j和E[i]合并。
值得一提的是,要注意空集的处理,所谓空集就是一开始的时候,每个人都没有敌人。
昨天晚上做了一晚上卡在了50分,今天又接着来啃,问同学,同学说我的想法很对,叫我自己慢慢调(WCNM我要是调的出来就不找你了)
没办法,慢慢找喽。
先给大家看看我的50分的代码。
#include <iostream> #include <cstdio> using namespace std; int n, m, Ans, x, y; int f[1008], E[1008]; char C; bool vis[1008]; int find(int x) { if(x == f[x]) return f[x]; else return f[x] = find(f[x]); } int main() { scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) f[i] = i; for(int i=1; i<=m; i++) { cin>>C>>x>>y; int xx, yy; if(C == 'E') { if(E[x] != 0) { f[y] = find(E[x]); } if(E[y] != 0) { f[x] = find(E[y]); } E[x] = y, E[y] = x; } if(C == 'F') { f[x] = find(y); } } for(int i=1; i<=n; i++) { if(!vis[find(i)]) { vis[find(i)] = 1; Ans++; } } printf("%d", Ans); }
不知道大家看出什么问题了没。
没看出的同学可要小心了,
看一下我的合并集合时候的操作,是不是把之前合并好的集合都打乱了。
为什么?因为我合并时修改的是f[x]的值,而不是f[find(x)]的值,这就会导致很可怕的错误。
往后的此类操作都是这样的。
好了,说到这里该放上AC的代码了
#include <iostream> #include <cstdio> using namespace std; int n, m, Ans, x, y; int f[1008], E[1008]; char C; bool vis[1008]; int find(int x) { if(x == f[x]) return x; else return f[x] = find(f[x]); } int main() { scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) f[i] = i; for(int i=1; i<=m; i++) { cin>>C>>x>>y; if(C == 'E') { if(E[x] != 0) { f[find(y)] = find(E[x]); } else E[x] = find(y); if(E[y] != 0) { f[find(x)] = find(E[y]); } else E[y] = find(x); } if(C == 'F') { f[find(x)] = find(y); } } for(int i=1; i<=n; i++) { if(!vis[find(i)]) { vis[find(i)] = 1; Ans++; } } printf("%d", Ans); }
转载于:https://www.cnblogs.com/bljfy/p/9085446.html
相关资源:数据结构—成绩单生成器