缩点:Power Plant;

题目传送门:[UVALive 6437]Power Plant

题目大意:T组数据,给定一幅带权图(n, m), 然后给定k个点, 与图中存在有若干条边。每个点都要至少要和这k个点的一个点直接或间接相连, 问最少的距离是多少。 1 ≤ T ≤ 100;

因为除了这k个点,其他的点是一个连通块,所以当前这个k点与其相连,我们并不需要知道原图中的点和i-k中哪个点相连,所以我们可以做一个超级汇点,让所有加的边与K相连;

即做了一个缩点的操作);做一遍最小生成树,那么这k个点必定会被选到;

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cmath>
#define MAXN 205
using namespace std;
struct node
{
       int u,v,d;
}e[MAXN*MAXN];
int father[MAXN];
int getfather(int x)
{
      if (father[x]==x) return x;
      return father[x]=getfather(father[x]);
}
bool cmp(node a,node b)
{
      return a.d<b.d;
}
int main()
{
      int C,ca,n,m,k,i,u,v,f,ans; 
      scanf("%d",&C);
      for (ca=1;ca<=C;ca++)
      {
               scanf("%d%d%d",&n,&m,&k);
               for (i=1;i<=n;i++) father[i]=i;
               scanf("%d",&f);
               for (i=2;i<=k;i++) scanf("%d",&u),father[u]=f;
               for (i=1;i<=m;i++)
                   scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].d);
               sort(e+1,e+1+m,cmp);
               ans=0;
               for (i=1;i<=m;i++)
               {
                        u=e[i].u,v=e[i].v;
                        int fx=getfather(u),fy=getfather(v);
                        if(fx!=fy)
                        {
                            father[fx]=fy;
                            ans+=e[i].d;
                        }
               }
               printf("Case #%d: %d\n",ca,ans);
      }
      return 0;
}

 

posted @ 2019-02-12 20:27  Tyouchie  阅读(269)  评论(0编辑  收藏  举报