zoukankan      html  css  js  c++  java
  • 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
    
    
    
     
  • 相关阅读:
    判断平面的一堆点是否在两条直线上
    约数的个数 + 贪心
    划分树板子
    如何获取前端提交来得json格式数据
    post 和php://input 转
    使用Guzzle执行HTTP请求
    redis集群搭建 不用ruby
    systemctl命令
    canal 配置 多个监听 推送到不同mq
    canal 整合RabbitMQ
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9456630.html
Copyright © 2011-2022 走看看