Luogu P1195/P1892 口袋的天空/BOI团伙 【最小生成树/并查集】By cellur925

其实这俩题挺水的,团伙拿下了一血,但是感觉还是写一下博客比较好x。

一、团伙

题目描述

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: 复制
6
4
E 1 4
F 3 5
F 4 6
E 1 2
输出样例#1: 复制
3

普普通通的并查集维护关系题,只是需要在“敌人的敌人也是朋友”上另加处理。
对于这层关系,我们可以另加一个数组next[],输入敌人关系时,
我们记录一下,当再输入到当前敌人的敌人信息时,就可以进行合并了。

code

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<iostream>
 4 
 5 using namespace std;
 6 
 7 int n,m,cnt;
 8 int f[1009],next[1009];
 9 
10 int getf(int x)
11 {
12     if(x==f[x]) return x;
13     else return getf(f[x]);
14 }
15 
16 void merge(int x,int y)
17 {
18     int pp=getf(x);
19     int qq=getf(y);
20     if(pp!=qq) f[qq]=pp;
21 }
22 
23 int main()
24 {
25     scanf("%d%d",&n,&m);
26     for(int i=1;i<=n;i++) f[i]=i;
27     for(int i=1;i<=m;i++)
28     {
29         char opt;
30         int x=0,y=0;
31         cin>>opt;
32         scanf("%d%d",&x,&y);
33         if(opt=='F')
34          merge(x,y);
35         if(opt=='E')
36         {
37             if(next[x]) merge(y,next[x]);
38             if(next[y]) merge(x,next[y]);
39             next[y]=x,next[x]=y;
40         }
41     }
42     for(int i=1;i<=n;i++)
43         if(f[i]==i) cnt++;
44     printf("%d",cnt); 
45     return 0;
46 }
View Code

 

 二、口袋的天空


我们看一看就知道这是生成树,但是与一般问题不同,这是在求k个生成树。
回顾Kruskal算法,我们可以相似地把这些边进行排序。不妨这样想:开始n个点都是独立的,他们可以近似看为n
个生成树。之后我们再一点点连边,减少生成树的数量直到k个就退出。

code

 1 #include<cstdio>
 2 #include<algorithm>
 3 
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 int n,m,k,x,y,z,tot,cnt;
 8 ll ans;
 9 int fa[10090];  
10 struct node{
11     int f,t,v;
12 }edge[20090];
13 
14 bool cmp(node a,node b)
15 {
16     return a.v<b.v;
17 }
18 
19 int getf(int x)
20 {
21     if(x==fa[x]) return x;
22     else return getf(fa[x]);
23 }
24 
25 int main()
26 {
27     scanf("%d%d%d",&n,&m,&k);cnt=n;
28     for(int i=1;i<=m;i++)
29     {
30         scanf("%d%d%d",&x,&y,&z);
31         edge[++tot].f=x;edge[tot].t=y;edge[tot].v=z;
32         edge[++tot].f=y;edge[tot].t=x;edge[tot].v=z;
33     }
34     sort(edge+1,edge+tot+1,cmp);
35     for(int i=1;i<=n;i++) fa[i]=i;
36     for(int i=1;i<=tot;i++)
37     {
38         int pp=getf(edge[i].f);
39         int qq=getf(edge[i].t);
40         if(pp!=qq)
41             fa[qq]=pp,cnt--,ans+=edge[i].v;
42         if(cnt==k) break;
43     }
44 //    printf("%d~~~~\n",cnt);
45     if(cnt<k) printf("No Answer");
46     else printf("%lld",ans);
47     return 0;
48 }
View Code

 

 
posted @ 2018-08-10 22:11  cellur925&Chemist  阅读(215)  评论(0编辑  收藏  举报