zoukankan      html  css  js  c++  java
  • 1386:打击犯罪(并查集)

    【题目描述】

        某个地区有n(n≤1000)个犯罪团伙,当地警方按照他们的危险程度由高到低给他们编号为1-n,他们有些团伙之间有直接联系,但是任意两个团伙都可以通过直接或间接的方式联系,这样这里就形成了一个庞大的犯罪集团,犯罪集团的危险程度由集团内的犯罪团伙数量唯一确定,而与单个犯罪团伙的危险程度无关(该犯罪集团的危险程度为n)。现在当地警方希望花尽量少的时间(即打击掉尽量少的团伙),使得庞大的犯罪集团分离成若干个较小的集团,并且他们中最大的一个的危险程度不超过n/2。为达到最好的效果,他们将按顺序打击掉编号1到k的犯罪团伙,请编程求出k的最小值。

    【题目链接】

        http://ybt.ssoier.cn:8088/problem_show.php?pid=1386

    【算法】

        1.二分/倍增+并查集(每次尝试都要重新构造并查集)

        2.逆序加点(维护一个并查集即可,不知道为啥,这个耗时更长。。。估计是稀疏图用邻接矩阵就很尴尬了)

    【代码1】

     

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int n;
     4 int G[1100][1100],fa[1100];
     5 int Get(int x)
     6 {
     7     if(fa[x]==x) return x;
     8     return fa[x]=Get(fa[x]);
     9 }
    10 void Merge(int x,int y)
    11 {
    12     fa[Get(x)]=Get(y);
    13 }
    14 bool valid(int k)
    15 {
    16     multiset<int> s;
    17     for(int i=k+1;i<=n;i++) fa[i]=i;
    18     for(int i=k+1;i<=n;i++)
    19         for(int j=k+1;j<=n;j++)
    20             if(G[i][j]) Merge(i,j);
    21     for(int i=k+1;i<=n;i++) {
    22         s.insert(Get(i));
    23         if(s.count(Get(i))>n/2) return false;
    24     }
    25     return true;
    26 }
    27 int main()
    28 {
    29     scanf("%d",&n);
    30     for(int i=1;i<=n;i++) {
    31         int a,num; scanf("%d",&num);
    32         while(num--) scanf("%d",&a),G[i][a]=1;
    33     }
    34     int l=1,r=n/2+1;
    35     while(l<r) {
    36         int mid=l+r>>1;
    37         if(valid(mid)) r=mid;
    38         else l=mid+1;
    39     }
    40     printf("%d
    ",l);
    41     return 0;
    42 }

    【代码2】

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 int n;
     4 int fa[1100],G[1100][1100];
     5 int Get(int x)
     6 {
     7     if(x==fa[x]) return x;
     8     return fa[x]=Get(fa[x]);
     9 }
    10 void Merge(int x,int y)
    11 {
    12     fa[Get(x)]=Get(y);
    13 }
    14 int main()
    15 {
    16     scanf("%d",&n);
    17     for(int i=1;i<=n;i++) {
    18         int num,a; scanf("%d",&num);
    19         while(num--) scanf("%d",&a),G[i][a]=1;
    20     }
    21     for(int i=1;i<=n;i++) fa[i]=i;
    22     for(int i=n;i>=1;i--) {
    23         multiset<int> s; bool flag=1;
    24         for(int j=i+1;j<=n;j++) {
    25             if(G[i][j]) Merge(i,j);
    26             if(G[j][i]) Merge(i,j);
    27         }
    28         for(int j=i;j<=n;j++) {
    29             s.insert(Get(j));
    30             if(s.count(Get(j))>n/2) flag=0;
    31         }
    32         if(!flag) { printf("%d
    ",i); return 0; }
    33     }
    34 }
  • 相关阅读:
    Linux 学习 step by step (1)
    ubuntu server nginx 安装与配置
    ubuntu server samba服务器配置
    iOS app集成支付宝支付流程及后台php订单签名处理
    mac 连接windows 共享内容
    linux 文件查找,which,whereis,locate,find
    ubuntu server vsftpd 虚拟用户及目录
    ubuntu server 安装 mantis bug tracker 中文配置
    ubuntu server vsftpd 匿名用户上传下载及目录设置
    linux 用户管理,用户权限管理,用户组管理
  • 原文地址:https://www.cnblogs.com/Willendless/p/9456998.html
Copyright © 2011-2022 走看看