http://poj.org/problem?id=3013
给出n个点,m个边。给出每个点的权值,每个边的权值。在m条边中选n-1条边使这n个点成为一棵树,root=1,求这棵树的最小费用,费用=树上每条边*子树中各顶点的权值。
思路:转化一下,发现每条边*子树中各定点的权值=各个点*点到根的最短路,于是转化成了root到各个点的最短路,又到不了的点则说明无法建树。
#pragma comment(linker, "/STACK:36777216") #pragma GCC optimize ("O2") #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <queue> #include <map> #include <iostream> #include <algorithm> using namespace std; #define RD(x) scanf("%d",&x) #define RD2(x,y) scanf("%d%d",&x,&y) #define RD3(x,y,z) scanf("%d%d%d",&x,&y,&z) #define clr0(x) memset(x,0,sizeof(x)) #define clr1(x) memset(x,-1,sizeof(x)) #define eps 1e-9 const double pi = acos(-1.0); typedef long long LL; typedef unsigned long long ULL; const int modo = 1e9 + 7; const int INF = 0x3f3f3f3f; const int inf = 0x3fffffff; const LL _inf = 1e18; const int maxn = 50005,maxm = 50005; struct edge{ int v,w,next; edge(){}; edge(int vv,int ww,int nnext):v(vv),w(ww),next(nnext){}; }e[maxm<<1]; int head[maxn],inq[maxn],vw[maxn]; LL dist[maxn]; int n,m,ecnt; void init() { clr1(head); ecnt = 0; fill(dist,dist+maxn,_inf); clr0(inq); } void add(int u,int v,int w) { e[ecnt] = edge(v,w,head[u]); head[u] = ecnt++; e[ecnt] = edge(u,w,head[v]); head[v] = ecnt++; } void spfa(int src) { queue<int> q; q.push(src);dist[src] = 0,inq[src] = 1; while(!q.empty()){ int cur = q.front(); q.pop();inq[cur] = 0; for(int i = head[cur];i != -1;i = e[i].next){ int nxt = e[i].v; if(dist[nxt] > dist[cur] + e[i].w){ dist[nxt] = dist[cur] + e[i].w; if(!inq[nxt]) inq[nxt] = 1,q.push(nxt); } } } } void work() { LL ans = 0; for(int i = 2;i <= n;++i){ if(dist[i] >= _inf){ puts("No Answer"); return ; } ans += dist[i] * vw[i]; } printf("%I64d\n",ans); } int main(){ int u,v,w,_; RD(_); while(_--){ RD2(n,m); init(); for(int i = 1;i <= n;++i) RD(vw[i]); while(m--){ RD3(u,v,w); add(u,v,w); } spfa(1); work(); } return 0; }