題意:數據結構
有一張有權無向圖,編號1的點爲根,要求一個生成樹,使得總花費sum(每條邊的花費×子樹全部節點花費的和)最小,輸出這個值。spa
分析:code
本身想了半天,永遠離不開生成樹上面,由於以前知道這個題是用最短路作的,想了半天也想不通爲何會是用最大路作的。blog
若是放在現場,本身確定作不出來。get
其實這題主要的思想轉化在於sum(每條邊的花費×子樹全部節點花費的和)這個公式。string
這個公式實際上是等價於sum(每條點的花費×該點到根的邊花費的和)。it
稍微想一想就能明白了。io
其餘的已經沒什麼難度了,無非是最短路而已。class
不過這題有坑,按道理n==0應該是輸出No Answer。queue
由於:
不過也發現本身的思惟真的很江化,算了,慢慢來。
腦子不夠就用經驗湊。
代碼:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 #include <vector> 6 7 8 using namespace std; 9 10 typedef long long ll; 11 const ll inf = 1ll<<60; 12 const int maxn=50010; 13 14 15 int t; 16 int n,m; 17 ll pa[maxn]; 18 19 struct Edge { 20 int v; 21 ll c; 22 }; 23 24 struct Node { 25 int v; 26 ll c; 27 Node(int _v,ll _c) { 28 v=_v,c=_c; 29 } 30 bool operator<(const Node &a)const { 31 return c>a.c; 32 } 33 }; 34 35 36 vector<Edge> edge[maxn]; 37 bool vis[maxn]; 38 ll dist[maxn]; 39 40 bool dijkstra(int n,int s) { 41 memset(vis,false,sizeof(vis)); 42 for(int i=1; i<=n; i++)dist[i]=inf; 43 priority_queue<Node> pq; 44 while(!pq.empty())pq.pop(); 45 dist[s]=0; 46 pq.push(Node(s,0)); 47 int cnt=0; 48 while(!pq.empty()) { 49 Node tmp = pq.top(); 50 pq.pop(); 51 int u=tmp.v; 52 if(vis[u])continue; 53 cnt++; 54 vis[u]=true; 55 for(int i=0; i<edge[u].size(); i++) { 56 int v = edge[u][i].v; 57 ll c = edge[u][i].c; 58 if(!vis[v]&&dist[v]>dist[u]+c) { 59 dist[v]=dist[u]+c; 60 pq.push(Node(v,dist[v])); 61 } 62 } 63 } 64 return cnt>=n; 65 } 66 67 int main() { 68 scanf("%d",&t); 69 while(t--) { 70 for(int i=0; i<=n; i++) { 71 edge[i].clear(); 72 } 73 scanf("%d%d",&n,&m); 74 for(int i=1; i<=n; i++) { 75 scanf("%lld",&pa[i]); 76 } 77 for(int i=0; i<m; i++) { 78 int u,v; 79 ll c; 80 scanf("%d%d%lld",&u,&v,&c); 81 edge[u].push_back(Edge{v,c}); 82 edge[v].push_back(Edge{u,c}); 83 } 84 if(n<=1) { 85 puts("0"); 86 continue; 87 } 88 if(dijkstra(n,1)) { 89 ll ans=0; 90 for(int i=2; i<=n; i++) { 91 ans+=dist[i]*pa[i]; 92 } 93 printf("%lld\n",ans); 94 } else { 95 puts("No Answer"); 96 } 97 98 } 99 100 101 return 0; 102 103 }