POJ 3013 Big Christmas Tree

POJ_3013

    如果按题目中的计算方法去想的话,是很难想到合适的算法的,而如果换个角度考虑问题的就海阔天空了。

    题目中是以边为中心去考虑的,如果我们以点为中心去考虑,最后的结果就是各点的点权和该点到根的边权和相乘之后再求和即可,于是只要根到每个点途径的边权和最小就行了,那么自然就是最短路了。

#include<stdio.h>
#include<string.h>
#define MAXD 50010
#define MAXM 100010
#define INF 1000000000000000ll
int N, M, D, a[MAXD], inq[MAXD], q[MAXD], first[MAXD], next[MAXM], v[MAXM], w[MAXM], e;
long long int d[MAXD];
void add(int x, int y, int z)
{
v[e] = y, w[e] = z;
next[e] = first[x];
first[x] = e;
++ e;
}
void init()
{
int i, j, x, y, z;
memset(first + 1, -1, sizeof(first[0]) * N);
e = 0;
for(i = 1; i <= N; i ++)
scanf("%d", &a[i]);
for(i = 0; i < M; i ++)
{
scanf("%d%d%d", &x, &y, &z);
add(x, y, z), add(y, x, z);
}
}
void solve()
{
int i, j, k, front, rear, x;
long long int ans;
for(i = 1; i <= N; i ++)
d[i] = INF;
d[1] = 0;
front = rear = 0;
q[rear ++] = 1;
memset(inq + 1, 0, sizeof(inq[0]) * N);
while(front != rear)
{
x = q[front ++];
if(front > N)
front = 0;
inq[x] = 0;
for(i = first[x]; i != -1; i = next[i])
if(d[x] + w[i] < d[v[i]])
{
d[v[i]] = d[x] + w[i];
if(!inq[v[i]])
{
inq[v[i]] = 1;
q[rear ++] = v[i];
if(rear > N)
rear = 0;
}
}
}
ans = 0;
for(i = 2; i <= N; i ++)
{
if(d[i] == INF)
{
printf("No Answer\n");
return ;
}
ans += a[i] * d[i];
}
printf("%lld\n", ans);
}
int main()
{
int t;
scanf("%d", &t);
while(t --)
{
scanf("%d%d", &N, &M);
init();
if(N == 0)
printf("0\n");
else
solve();
}
return 0;
}


原文地址:https://www.cnblogs.com/staginner/p/2404185.html