• 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~~~~
    ",cnt);
    45     if(cnt<k) printf("No Answer");
    46     else printf("%lld",ans);
    47     return 0;
    48 }
    View Code
    
    
    
     
  • 相关阅读:
    nginx 安全请求头
    使用citus 列式存储压缩数据
    nginx ngx_http_realip 的功能以及使用
    act 的密钥&&环境变量管理
    oracle怎么查询重复的数据
    如何在Oracle中复制表结构和表数据
    2022成都.NET开发者Connect线下活动
    闭包具有逻辑内聚的功能
    编程范式是人类思维方式的投影代表了程序设计者认为程序应该如何被构建和执行的看法
    工程师是高级生产者
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9456630.html
Copyright © 2020-2023  润新知