1. 程式人生 > >BZOJ 1232 [Usaco2008Nov]安慰奶牛cheer:最小生成樹【樹上dfs性質】

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

space bsp void pre print 一次 targe algorithm names

題目鏈接: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 }

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