• 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 }
  • 相关阅读:
    Ubuntu 11.04 安装后要做的20件事情
    Net 服务命令行参考之一
    Openerp约束句型
    Ubuntu进入Shell
    postgreSql基础命令及linux下postgreSql命令
    解决中文乱码的问题
    An error occured while handling a json request
    Java Socket编程
    CentOS 7 中 Docker 的安装和卸载
    Spring Boot整合shiro-登录认证和权限管理
  • 原文地址:https://www.cnblogs.com/Willendless/p/9456998.html
Copyright © 2020-2023  润新知