ZOJ 1456 Minimum Transport Cost
1 算法
floyd+path[i][j]记录从源点为i,终点为j的路径上i的后继节点。
dijkstra或spfa(对于此稠密图,spfa需加lll或slf优化),从终点t到源点s逆向求最短路径, 对从t出发到当前节点v的所有最短路径中,选择序号最小的父节点作为v的前驱节点pre[v], 可保证输出最小字典序,不逆向会出现如下情况:
当存在边:
1 3 6
1 2 2
2 5 4
3 4 1
5 4 1
s=1,t=4,当选择最小的父节点做t的前驱节点时,结果为1--3--4,而最小字典序为1--2--5--4。
2 代码
#include <iostream>
#include <cmath>
#include <cstring>
#include <cstdio>
using namespace std;
#define N 2010
int a[N][N];
int wei[N];
int pre[N];
int q[N];
int qf, ql;
int dis[N];
bool inq[N];
int n;
int sou, tar;
void read_data()
{
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
scanf("%d", &a[j][i]);
for (int i = 0; i < n; ++i)
scanf("%d", &wei[i]);
}
void dijkstra()
{
int u, v;
int mindis;
memset(inq, 0, sizeof(inq));
memset(dis, 0x3f, sizeof(dis));
inq[sou] = true;
dis[sou] = 0;
for (int i = 0; i < n; ++i)
if (!inq[i] && a[sou][i] != -1)
{
dis[i] = dis[sou] + wei[sou] + a[sou][i];
pre[i] = sou;
}
for (int k = 1; k < n; ++k)
{
mindis = 0x3f;
for (int i = 0; i < n; ++i)
if (!inq[i] && dis[i] < mindis)
{
mindis = dis[i];
u = i;
}
inq[u] = true;
for (v = 0; v < n; ++v)
if (!inq[v] && a[u][v] != -1)
{
if (dis[u] + wei[u] + a[u][v] < dis[v])
{
dis[v] = dis[u] + wei[u] + a[u][v];
pre[v] = u;
}
if (dis[u] + wei[u] + a[u][v] == dis[v])
if (pre[v] > u) pre[v] = u;
}
}
}
void spfa()
{
int num;
double ave;
memset(inq, 0, sizeof(inq));
memset(dis, 0x3f, sizeof(dis));
memset(pre, 0xff, sizeof(pre));
inq[sou] = true;
dis[sou] = 0;
qf = ql;
q[ql++] = sou;
num = 1;
ave = 0;
while (qf != ql)
{
int u = q[qf++];
if (qf == N) qf = 0;
if (num > 1)
ave = (ave * num - dis[u]) / (num - 1);
else
ave = 0;
num--;
for (int v = 0; v < n; ++v)
if (v != u && a[u][v] != -1)
{
if (dis[u] + wei[u] + a[u][v] < dis[v])
{
dis[v] = dis[u] + wei[u] + a[u][v];
pre[v] = u;
if (!inq[v])
{
if (dis[v] < ave)
{
if (qf == 0) qf = N;
qf--;
q[qf] = v;
}
else
{
q[ql++] = v;
if (ql == N) ql = 0;
}
ave = (ave * num + dis[v]) / (num + 1);
num++;
inq[v] = true;
}
}
if (dis[u] + wei[u] + a[u][v] == dis[v])
if (pre[v] > u) pre[v] = u;
}
inq[u] = false;
}
}
int main()
{
while (scanf("%d", &n) && n != 0)
{
read_data();
while (scanf("%d%d", &tar, &sou) && tar != -1 && sou != -1)
{
int d;
sou--;
tar--;
if (sou != tar)
{
spfa();
d = dis[tar] - wei[sou];
}
else
d = 0;
printf("From %d to %d :\n", tar + 1, sou + 1);
printf("Path: %d", tar + 1);
while (tar != sou)
{
tar = pre[tar];
printf("-->%d", tar + 1);
}
printf("\nTotal cost : %d\n\n", d);
}
}
return 0;
}