BZOJ 1232 [Usaco2008Nov]安慰奶牛cheer:最小生成树【树上dfs性质】

题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1232

题意:

  给你一个无向图,n个点,m条边。

  每条边有边权len[i][j],每个点有点权c[i]。

  让你找一棵生成树,并在这棵树上找一个根。

  从根开始dfs整棵树,每经过一条边(或一个点),花费加上对应的边权(点权)。

  问你最小的花费。

 

题解:

  树上dfs性质:

    花费 = ∑ (2*len[i][j] + c[i] + c[j]) + c[root]

    (1)每一条边要经过两次。

    (2)每一条边的两个端点会分别被经过一次。

    (3)起点要多经过一次。

 

  所以加边的时候,边权要设为 2*len[i][j] + c[i] + c[j]。

  跑一遍kruskal,然后给答案加上最小的一个点权。

 

AC Code:

  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <string.h>
  4 #include <algorithm>
  5 #include <vector>
  6 #define MAX_N 10005
  7 #define INF 10000000
  8 
  9 using namespace std;
 10 
 11 struct Edge
 12 {
 13     int sour;
 14     int dest;
 15     int len;
 16     Edge(int _sour,int _dest,int _len)
 17     {
 18         sour=_sour;
 19         dest=_dest;
 20         len=_len;
 21     }
 22     Edge(){}
 23     friend bool operator < (const Edge &a,const Edge &b)
 24     {
 25         return a.len<b.len;
 26     }
 27 };
 28 
 29 int n,m;
 30 int ans;
 31 int c[MAX_N];
 32 int par[MAX_N];
 33 vector<Edge> edge;
 34 
 35 void init_union_find()
 36 {
 37     for(int i=1;i<=n;i++)
 38     {
 39         par[i]=i;
 40     }
 41 }
 42 
 43 int find(int x)
 44 {
 45     return par[x]==x?x:par[x]=find(par[x]);
 46 }
 47 
 48 void unite(int x,int y)
 49 {
 50     int px=find(x);
 51     int py=find(y);
 52     if(px==py) return;
 53     par[px]=py;
 54 }
 55 
 56 bool same(int x,int y)
 57 {
 58     return find(x)==find(y);
 59 }
 60 
 61 int kruskal()
 62 {
 63     init_union_find();
 64     sort(edge.begin(),edge.end());
 65     int cnt=0;
 66     int res=0;
 67     for(int i=0;i<edge.size();i++)
 68     {
 69         Edge temp=edge[i];
 70         if(!same(temp.sour,temp.dest))
 71         {
 72             cnt++;
 73             res+=temp.len;
 74             unite(temp.sour,temp.dest);
 75         }
 76     }
 77     return cnt==n-1?res:-1;
 78 }
 79 
 80 void read()
 81 {
 82     cin>>n>>m;
 83     for(int i=1;i<=n;i++)
 84     {
 85         cin>>c[i];
 86     }
 87     int a,b,v;
 88     for(int i=0;i<m;i++)
 89     {
 90         cin>>a>>b>>v;
 91         edge.push_back(Edge(a,b,2*v+c[a]+c[b]));
 92     }
 93 }
 94 
 95 int find_min()
 96 {
 97     int minn=INF;
 98     for(int i=1;i<=n;i++)
 99     {
100         minn=min(minn,c[i]);
101     }
102     return minn;
103 }
104 
105 void solve()
106 {
107     ans=kruskal();
108     ans+=find_min();
109 }
110 
111 void print()
112 {
113     cout<<ans<<endl;
114 }
115 
116 int main()
117 {
118     read();
119     solve();
120     print();
121 }

 

posted @ 2017-10-03 19:37  Leohh  阅读(160)  评论(0编辑  收藏  举报