一.P1982 团伙
1.本题依旧是紧张刺激的并查集(>-<),原理是用树维护集合,树根编号为集合编号。
int find(int x){
if(f[x]!=x) f[x]=find(f[x]);
return f[x];
}
2.Friend合并,Enemy记录,再把下一个Enemy和记录的Enemy合并。因为敌人的敌人是朋友。比如 E 1 2, E 2 3,记录E[1] = 2, E[2] = 1现在到了E 2 3,E[2]有了,那么把1,3合并,然后记录E[3] = 2。由于敌人的敌人已经合并,那么这时的1或者3都是2的敌人,取一个代表就行,下次再碰到2和某个人是敌人,把他和1合并或把它和3合并是一样的。连通块在合并的时候统计就可以了。
3. (1)对于两个人之间的关系,可以不存在关系,记录下不能合并的关系,再次找到时合并可以合并的人
(2)对于两个人之间的关系,一定存在关系,用带权并査集
void un(int x,int y){
if(find(x)!=find(y)){
res--;
f[find(x)]=find(y);
}
}
for(int i=1;i<=n;i++) f[i]=i;
res=n;
for(int i=1;i<=m;i++){
char op[10];
int x, y;
scanf("%s%d%d",op,&x,&y);
if(op[0]=='F') un(x,y);
else{
if(e[y]) un(x,e[y]);
else e[y] = x;
if(e[x]) un(y,e[x]);
else e[x]=y;
}
}
printf("%d", res);
二.P1491 集合位置
1.这是次短路问题(很明显吧)顾名思义,就是仅次于图中最短路的最短的路。
2.采用删边的思想,先跑一遍最短路并记录下来。
然后依次删去最短路径上每一条边,分别跑一遍最短路,取所有答案中的最小值。
(不去掉最短路上的边,最短路没有变化)
3.在跑第一遍最短路的时候记录被更新的点的前驱,(只有第一次跑,才要记录路径)
4.本题没有负边权,建议Dijkstra+堆优化(注意数据类型是double)
PS:思路不顺望见谅