ZOJ 1456 Minimum Transport Cost

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值