• hihocoder 1160 : 攻城略地


    描述

    A、B两国间发生战争了,B国要在最短时间内对A国发动攻击。已知A国共有n个城市(城市编号1, 2, …, n),城市间有一些道路相连。每座城市的防御力为w,直接攻下该城的代价是w。若该城市的相邻城市(有道路连接)中有一个已被占领,则攻下该城市的代价为0。

    除了占领城市,B国还要摧毁A国的交通系统,因而他们需要破坏至少k条道路。由于道路损毁,攻下所有城市的代价相应会增加。假设B国可以任意选择要摧毁的道路,那么攻下所有城市的最小代价是多少?

    输入

    第一行一个整数T,表示数据组数,以下是T组数据。

    每组数据第一行包含3个整数n, m, k。

    第二行是n个整数,分别表示占领城市1, 2, …, n的代价w。

    接下来m行每行两个数i, j,表示城市i与城市j间有一条道路。

    输出

    对于每组数据输出一行,格式为"Case #X: Y"。X表示数据编号(从1开始),Y为答案。

    数据范围

    1 ≤ T ≤ 30

    k ≤ m

    0 ≤ w ≤ 108

    小数据

    1 ≤ n ≤ 1000

    0 ≤ m ≤ 5000

    大数据

    1 ≤ n ≤ 106

    0 ≤ m ≤ 106

    样例输入

    2
    4 4 2
    6 5 3 4
    1 2
    1 3
    2 3
    2 4
    4 4 4
    6 5 3 4
    1 2
    1 3
    2 3
    2 4
    

    样例输出

    Case #1: 7
    Case #2: 18

    题解:
      首先,我们按题目顺序进行加边,如果这个边连的两个点已经联通,那么这个边就是不必要的,就可以直接删除。
      然后我们考虑删除之后怎么做,如果还要继续删除,那么我们把每个联通块的最小点权先加上,然后把其他的点排序,显然剩下的必然会多产生剩下边数个联通块,因为是一个森林,所以一定可以取到前剩余边个最小点,把点权加上就可以了。
    代码:(by zzl)
    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int MAXN=2200000,INF=0x3f3f3f3f;
    int T,n,m,k,top,CNT;
    LL ans;
    int fa[MAXN],v[MAXN],que[MAXN];
    void clear()
    {
       ans=top=0;
       for(int i=1;i<=n;i++)fa[i]=i;
    }
    int find(int x)
    {
       if(x!=fa[x])
          fa[x]=find(fa[x]);
       return fa[x];
    }
    void Union(int x,int y)
    {
       x=find(x); y=find(y);
       if(v[x]<v[y])swap(x,y);
       fa[x]=y;
    }
    int main()
    {
       scanf("%d",&T);
       while(T--)
          {
         scanf("%d%d%d",&n,&m,&k);
         clear();
         for(int i=1;i<=n;i++)scanf("%d",&v[i]);
         for(int i=1,a,b;i<=m;i++)
            {
               scanf("%d%d",&a,&b);
               if(find(a)!=find(b))
                 Union(a,b);
               else
              k--;
            }
         for(int i=1;i<=n;i++)
            if(find(i)==i)
               ans+=v[i];
            else
               que[++top]=v[i];
         if(k<=0)
            {
               printf("Case #%d: %lld
    ",++CNT,ans);
               continue;
            }
         sort(que+1,que+1+top);
         for(int i=1;i<=k;i++)
            ans+=que[i];
         printf("Case #%d: %lld
    ",++CNT,ans);
          }
       return 0;
    }
  • 相关阅读:
    CSS命名
    纯html网页重定向与跳转
    display:none与visible:hidden的区别
    添加弹窗视频
    表格
    get请求报文
    解决maven下载jar慢的问题(如何更换Maven下载源)
    Java开发第一步:JDK 7 安装及配置
    安卓开发第一步:Android Studio安装配置
    IntelliJ IDEA 导入新项目以后的简单配置
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7573915.html
Copyright © 2020-2023  润新知