这道题目有点长,看了半天才看懂啥意思。
就是有n个车站,m条路线,每条路线有一个价格。
要求从起始站到每一站,然后再从每一站回去,求最少的钱数。
看起来就是最短路径的问题,就是求单源点到其他各点的最但距离(票价),然后建个反向图,求的返回的钱数。加起来就行了。
最短路径很多方法,Dijkstra算法,Bell-ford算法,floyd-washall,以及本题目用的spfa算法。
由于数据比较大,Dijkstra算法 (o(n^2)) floyd-washall(o(n^3))肯定会超时。
其实spfa比Dijkstra算法还要简单,代码更少,就是维护一个队列,队列里面放着可能经过的点,知道队列为空。
注意要用邻接表保存图,邻接矩阵会超内存的。
代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define nMax 1000010
#define eMax 10000010
#define inf 1000000010
struct EDGE
{
int v,w,next;
}edge[nMax], reEdge[nMax];
int nEdge[nMax], nReEdge[nMax];
int n, m, queue[eMax];
__int64 dis[nMax], sum;
bool vis[nMax];
void edgeInit()
{
for (int i = 1; i <= n; ++ i)
{
nEdge[i] = 0;
nReEdge[i] = 0;
}
}
void spfaInit()
{
for (int i = 1; i <= n; ++ i)
{
dis[i] = inf;
vis[i] = false;
}
}
void spfa(int * nEdge, EDGE * edge)
{
spfaInit();
int head = 0, tail = 1;
dis[1] = 0;
queue[0] = 1;
while (head < tail)
{
int u = queue[head];
vis[u] = true;
int p = nEdge[u];
while (p != 0)
{
int v = edge[p].v, w = edge[p].w;
if (dis[v] > dis[u] + w)
{
dis[v] = dis[u] + w;
if (!vis[v])
{
vis[v] = true;
queue[tail] = v;
tail ++;
}
}
p = edge[p].next;
}
vis[u] = false;
head ++;
}
for (int i = 1; i <= n; ++ i)
{
sum += dis[i];
}
}
int main()
{
int t;
scanf("%d", &t);
while (t --)
{
scanf("%d%d", &n, &m);
edgeInit();
for (int i = 1; i <= m; ++ i)
{
int u, v, w;
scanf("%d%d%d", &u, &v, &w);
edge[i].v = v;
edge[i].w = w;
edge[i].next = nEdge[u];
nEdge[u] = i;
reEdge[i].v = u;
reEdge[i].w = w;
reEdge[i].next = nReEdge[v];
nReEdge[v] = i;
}
sum = 0;
spfa(nEdge, edge);
spfa(nReEdge, reEdge);
printf("%I64d\n", sum);
}
return 0;
}