POJ 3013
//算法实现:Dijkstra+邻接表+优先级队列
//解题思路:由于是构造一棵树,则最终所求答案ans = ∑dist[i] * weight[i].(1 <= i <= vn),其中dist[i]为结点i到根结点root(1)的距离,vn为结点数,
//而且weight[i]是固定的,ans仅仅与dist[i]有关。这样就转换成了求各点到根结点的最短路径。
#include <iostream>
#include <algorithm>
#include <queue>
#include <climits> //引入<climits>的类,注意如果引入<limits>会出现编译错误
#include <cstdio>
//#include <conio.h>
using namespace std;
typedef unsigned long long u64_T; //类型定义
const int MAXN = 50001;
const u64_T INF=(u64_T)(1)<<63; //这种方法比较常用
//const u64_T INF = ULLONG_MAX; //定义unsigned long long 的最大值
struct edge_T {
int v;
u64_T w;
edge_T *next;
}*adj[MAXN], edges[2*MAXN]; //adj[i]存储以i为起点的邻接表的指针,memo[]存储所有的边
struct node_T { //用于优先级队列中记录节点的标号和最短路径
int v;
u64_T len;
bool operator < (const node_T &nod) const { //重载优先级队列的操作符,使其从小到大排列(注意格式必须完全一致)
return len > nod.len;
}
};
int edgenum; //记录边的总数
u64_T weight[MAXN];
bool final[MAXN]; //Dijkstra算法中记录该节点是否找到了最短路,为true代表已经找到了最短路径
int vn,en; //记录定点数和边数
void addEdge(int u, int v, u64_T w) {
edge_T *ptr = &edges[edgenum ++];
ptr -> v = v;
ptr -> w = w;
ptr -> next = adj[u]; //往前插入边
adj[u] = ptr;
}
u64_T dijkstra(int s) { //n代表结点总数
priority_queue <node_T> Q; //使用优先级队列实现
node_T cur;
cur.v = s;
cur.len = 0;
Q.push(cur);
u64_T dist[MAXN]; //存储结点的最小距离
for(int i = 1; i <= vn; i ++) dist[i] = INF; //除源点以外的所有点的距离设置成无穷大(此处与邻接阵实现不同,临界阵赋值为到源点的距离,这里也可但是麻烦
dist[s] = 0;
final[s] = true;
while(! Q.empty()) {
int v = Q.top().v; //优先级队列使用top()
u64_T len = Q.top().len;
Q.pop();
final[v]=true;
for(edge_T *ptr = adj[v]; ptr; ptr = ptr -> next) {
int u = ptr -> v;
u64_T w = ptr -> w;
if(!final[u] && dist[v] + w < dist[u]) {
dist[u] = dist[v] + w;
cur.v = u;
cur.len = dist[u];
Q.push(cur);
}
}
}
for(int i = 1; i <= vn; i ++) {
if(dist[i] == INF)
return INF;
}
u64_T minimumCost = 0;
for(int i = 1; i <= vn; i ++) {
minimumCost += dist[i] * weight[i];
}
return minimumCost;
}
int main() {
//freopen("1.txt","r",stdin);
int casn;
scanf("%d", &casn);
while(casn --) {
int i;
scanf("%d %d", &vn, &en);
for(i = 1; i <= vn; i ++) {
//scanf("%I64u", &weight[i]); //读取unsigned long long的两种方法
scanf("%llu", &weight[i]);
adj[i] = NULL; //初始化邻接表的指针
}
edgenum = 0; //初始化边数
int u, v;
u64_T w;
for(i = 1; i <= en; i ++) { //双向边
//scanf("%d%d%I64u", &u, &v, &w); 两种读取方式皆可
scanf("%d%d%llu", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
memset(final,0,sizeof(final)); //初始化
u64_T minimumCost = dijkstra(1);
if(minimumCost == INF)
printf("No Answer\n");
else
//printf("%I64u\n", minimumCost);
printf("%llu\n", minimumCost);
}
//getch();
return(0);
}