哈理工oj(acm.hrbust.edu.cn) 1419【dijkstra + 邻接表 + 堆优化】
Description |
为了给集训队的训练环境带来点高雅的感觉 ~ 集训队的女队友们决定买些花来作为点缀,可是如果买真花的话会很快枯萎,所以她们决定定制一株假花,它们不会枯萎而且也很漂亮。 每棵假花可以用一些点和边来表示,点表示花朵,边表示枝,点被标记为1到n,每棵假花有一个根,规定为1号,每一个点有一个可能不同的造价,每条边也可能不同,所以它们的造价也可能不同,每棵子树定价规定为(所有该子树上的节点的造价和)*(连接该子树与其父节点的边的造价和)。 她们希望这株假花尽可能的大,但又想在保持花的节点数不变的情况下使用尽量小的花费,现在请你来编程帮忙解决这个问题。 |
Input |
输入包含T组,首先给出T的值,每组数据首先给出v,e(0<=v,e<=50000)表示节点数与边数,然后给出一行有v个整数,每个整数wi表示第i个节点的造价,接着是e行,每行有三个整数a,b,c表示a,b节点可以边一条造价为c的边, 所以输入数据不大于2^16。 |
Output |
对于每组数据,输入定制这株假花需要的可能最小花费,如果无法制作这株假花,输出“No Answer”。 |
Sample Input |
2 2 1 1 1 1 2 15 7 7 200 10 20 30 40 50 60 1 2 1 2 3 3 2 4 2 3 5 4 3 7 2 3 6 3 1 5 9
|
Sample Output |
15 1210 |
View Code
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int MAXN = 50000 + 10; typedef long long llong; struct node { int v, len; struct node *next; }; int nE; node Edge[MAXN * 2]; node *head[MAXN]; void add_edge(int u, int v, int len) { node *e = Edge + nE++; e->v = v; e->len = len; e->next = head[u]; head[u] = e; } struct Node { int v; llong len; bool operator < (const Node &B) const { return len > B.len; } } vHeap[MAXN]; bool vis[MAXN]; void dijkstra(int n, int s, node *head[], llong len[]) { memset(vis, 0, sizeof(vis[0]) * (n+1)); memset(len, -1, sizeof(len[0]) * (n+1)); len[s] = 0; int cnt = 1;//堆指针。 vHeap[0].v = s; vHeap[0].len = 0; for(int i = 0; i < n; i++) { int u = -1;//离顶点最短距离的点。 llong minLen = -1; //最短距离。 while(cnt > 0) { u = vHeap[0].v; minLen = vHeap[0].len; pop_heap(vHeap, vHeap + cnt); //从新构建堆。 cnt--; if(!vis[u]) { break; } u = -1; } if(u == -1) { break; } vis[u] = 1;//第一次循环是顶点,因为在循环外面并没有将顶点加入到集合vis里面。 for(node *e = head[u]; e; e = e->next) { if(!vis[e->v] && (len[e->v] == -1 || len[e->v] > minLen + e->len)) { len[e->v] = minLen + e->len;//更新最短长度。 vHeap[cnt].v = e->v;//继续构建堆,所以从cnt开始。 vHeap[cnt].len = len[e->v]; cnt++; push_heap(vHeap, vHeap+cnt); } } } } int pr_node[MAXN]; llong len[MAXN]; int main() { int i, j; int nTest; scanf("%d", &nTest); while( nTest-- ) { int n, e; scanf("%d %d", &n, &e); for(i = 1; i <= n; i++) { scanf("%d", &pr_node[i]); } nE = 0; memset(head, 0, sizeof(head)); for(i = 0; i < e; i++) { int u, v, len; scanf("%d %d %d", &u, &v, &len); add_edge(u, v, len); add_edge(v, u, len); } dijkstra(n, 1, head, len); llong ans = 0; for(i = 1; i <= n; i++) { if(len[i] < 0) { ans = -1; break; } ans += pr_node[i] * len[i]; } if(ans >= 0) { printf("%lld\n", ans); } else { printf("No Answer\n"); } } return 0; }