POJ 3013:Big Christmas Tree

来源:互联网 发布:淘宝商品7天自动下架 编辑:程序博客网 时间:2024/06/07 10:29


Big Christmas Tree
Time Limit: 3000MS Memory Limit: 131072KTotal Submissions: 24201 Accepted: 5249

Description

Christmas is coming to KCM city. Suby the loyal civilian in KCM city is preparing a big neat Christmas tree. The simple structure of the tree is shown in right picture.

The tree can be represented as a collection of numbered nodes and some edges. The nodes are numbered 1 through n. The root is always numbered 1. Every node in the tree has its weight. The weights can be different from each other. Also the shape of every available edge between two nodes is different, so the unit price of each edge is different. Because of a technical difficulty, price of an edge will be (sum of weights of all descendant nodes) × (unit price of the edge).

Suby wants to minimize the cost of whole tree among all possible choices. Also he wants to use all nodes because he wants a large tree. So he decided to ask you for helping solve this task by find the minimum cost.

Input

The input consists of T test cases. The number of test cases T is given in the first line of the input file. Each test case consists of several lines. Two numbers ve (0 ≤ ve ≤ 50000) are given in the first line of each test case. On the next line, v positive integers wi indicating the weights of v nodes are given in one line. On the following e lines, each line contain three positive integers abc indicating the edge which is able to connect two nodes a and b, and unit price c.

All numbers in input are less than 216.

Output

For each test case, output an integer indicating the minimum possible cost for the tree in one line. If there is no way to build a Christmas tree, print “No Answer” in one line.

Sample Input

22 11 11 2 157 7200 10 20 30 40 50 601 2 12 3 32 4 23 5 43 7 23 6 31 5 9

Sample Output

151210

题目翻译:

给出V个节点E条边。然后给出V个节点的权值,给出某些节点之间边的权值,现在要用这N个节点构成圣诞树(节点1永远作为根),需要边来连接圣诞树中的节点。

圣诞树的边 u-v 的价值等于边 u-v 的权值*(v所在子树中的所有节点的权重和)。求构成圣诞树的最小花费,如果够不成N个节点的数,输出No Answer.

以题目中的图为例。

1-2这条边的价格= weight12 * (nodeweight2+nodeweight3+nodeweight4+nodeweight5+nodeweight6+nodeweight7)

其实对于一个节点,它在走到根节点所经过的每一条路,都需要乘上这个节点的权值。因为这个节点是它所路过节点的子节点,

所以所有路过的边都会成上这个节点的权值。因为一个节点的权值是定值,我们当然希望它距离1的距离越近越好。因此这个题

就是要求所有点到源点1的最短路径在乘上权值的和即是答案。最开始真的没有看出来这是个最短路的题目。需要分析一下才能

知道,它到底要考察什么知识。

注意两个特殊数据:V = 0 和 1 的情况,V = 1时千万不要去输出节点1的权值。要读明白题,构成圣诞树的花费是指

圣诞树中边的最小花费,不要把节点的权值也看成花费了。所以V=1的时候,只有1一个节点,不需要任何边去构成

圣诞树,所以最小花费就是0。还有就是INF要大一些,否则hold不住后台的数据。最短路的值有点大。

最后一点普通Dijkstra会超时,可以用Dijkstra+heap或Shorest Path Fast Algorithm(SPFA)去写。


#include<iostream>#include<stdio.h>#include<cstring>#include<algorithm>#include<string>#include<queue>#define INF 0x3f3f3f3f3fusing namespace std;const int maxn = 50004;int V,E;            /// V为节点个数,E为边的条数。int weight[maxn];   /// 存放每个节点的权值。int head[maxn];struct Edge{    int v;    long long int w;    int next;}edge[maxn<<2];void SPFA(int start){    queue<int>qu;    int vis[maxn];    long long int dis[maxn];    for(int i = 1; i <= V; i++)    {        dis[i] = INF;        vis[i] = 0;    }    int now,nex;    vis[1] = 1;    dis[1] = 0;    qu.push(1);    while(!qu.empty())    {        now = qu.front();        qu.pop();        vis[now] = 0;        for(int i = head[now]; i != -1; i = edge[i].next)        {            nex = edge[i].v;            if(dis[now]+edge[i].w < dis[nex])            {                dis[nex] = dis[now]+edge[i].w;                if(vis[nex]==0)                {                    vis[nex] = 1;                    qu.push(nex);                }            }        }    }    long long ans = 0;    for(int i = 1; i <= V; i++)    {        if(dis[i]<INF)            ans += weight[i]*dis[i];        else        {            printf("No Answer\n");            return;        }    }    printf("%lld\n",ans);}int main(){    int T;    int a,b,c;    scanf("%d",&T);    while(T--)    {        scanf("%d%d",&V,&E); ///节点个数,E是边的个数        for(int i = 1; i <= V; i++)        {            scanf("%d",&weight[i]);            head[i] = -1;        }        int j = 0;        for(int i = 1; i <= E; i++)        {            scanf("%d%d%lld",&a,&b,&c);            edge[j].v = b;            edge[j].w = c;            edge[j].next = head[a];            head[a] = j;            j++;            edge[j].v = a;            edge[j].w = c;            edge[j].next = head[b];            head[b] = j;            j++;        }        if(V == 0 || V == 1) printf("0\n");        else SPFA(1);    }    return 0;}



0 0
原创粉丝点击