题目大意:给你 n 个节点,编号从1 到 n ,节点 1 为根节点,并且每个节点都有一个重量 w ,现在要在这些点之间建设公路,要求必须包含所有节点并且使整个图连通,总费用为 每条边的单价 * (该边所有子节点的重量之和) 。其实这是一个最短路的问题,经过推倒,总费用 = 每个节点的重量 * 该节点到根节点(节点1)的最短路径。
Ps:此题卡精度 , 需用long long , int 范围不够, double 精度不够 。
请看代码:
#include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<vector> #include<queue> #define mem(a , b) memset(a , b , sizeof(a)) using namespace std ; const int MAXN = 5e4 + 5 ; const long long INF = 0x7fffffffffffffff ; long long dis[MAXN] ; int w[MAXN] ; struct Edge { int adj ; int d ; int next ; } e[MAXN * 2] ; int n , se ; int ecnt ; int head[MAXN] ; bool inq[MAXN] ; int root ; void chu() { ecnt = 0 ; mem(head , -1) ; mem(inq , 0) ; root = 1 ; } void init() { scanf("%d%d" , &n , &se) ; int i ; for(i = 1 ; i <= n ; i ++) { scanf("%d" , &w[i]) ; } for(i = 0 ; i < se ; i ++) { int a , b , d ; scanf("%d%d%d" , &a , &b , &d) ; e[ecnt].adj = b ; e[ecnt].d = d ; e[ecnt].next = head[a] ; head[a] = ecnt ; ecnt ++ ; e[ecnt].adj = a ; e[ecnt].d = d ; e[ecnt].next = head[b] ; head[b] = ecnt ; ecnt ++ ; } } queue<int> q ; void spfa() { while (!q.empty()) q.pop() ; q.push(root) ; inq[root] = true ; int tmp ; while (!q.empty()) { tmp = q.front() ; q.pop() ; inq[tmp] = false ; int i ; for(i = head[tmp] ; i != -1 ; i = e[i].next) { Edge t = e[i] ; int tv ; tv = t.adj ; int td = t.d ; if(dis[tmp] < INF && dis[tmp] + td < dis[tv]) { dis[tv] = dis[tmp] + td ; if(!inq[tv]) { inq[tv] = true ; q.push(tv) ; } } } } } void solve() { if(n == 0 || n == 1) { printf("0\n") ; return ; } int i ; for(i = 1 ; i <= n ; i ++) { dis[i] = INF ; } dis[1] = 0 ; spfa() ; long long ans = 0 ; for(i = 1; i <= n ; i ++) { if(dis[i] == INF) { printf("No Answer\n") ; return ; } ans += w[i] * dis[i] ; } printf("%lld\n" , ans) ; } int main() { int T ; scanf("%d" , &T) ; while (T --) { chu() ; init() ; solve() ; } return 0 ; }