zoukankan      html  css  js  c++  java
  • 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;
    }
  • 相关阅读:
    背水一战 Windows 10 (26)
    背水一战 Windows 10 (25)
    背水一战 Windows 10 (24)
    背水一战 Windows 10 (23)
    背水一战 Windows 10 (22)
    背水一战 Windows 10 (21)
    背水一战 Windows 10 (20)
    背水一战 Windows 10 (19)
    背水一战 Windows 10 (18)
    背水一战 Windows 10 (17)
  • 原文地址:https://www.cnblogs.com/renjianshige/p/7573915.html
Copyright © 2011-2022 走看看