HDU 1385 Minimum Transport Cost:最短路,打印字典序路径

链接:

http://acm.hdu.edu.cn/showproblem.php?pid=1385

题目大意:

有N个城市,然后直接给出这些城市之间的邻接矩阵,矩阵中-1代表那两个城市无道路相连,其他值代表路径长度。

如果一辆汽车经过某个城市,必须要交一定的钱(可能是过路费)。

现在要从a城到b城,花费为路径长度之和,再加上除起点与终点外所有城市的过路费之和。

求最小花费,如果有多条路经符合,则输出字典序最小的路径。

分析与总结:

1.   这题的关键在于按照字典序输出路径。

假设有

1--->2  2

2--->3  1

1--->3  3

求1到3的最小花费路径.

那么显然后两条路:

1-->3   3

1-->2-->3  3

它们的花费是相同的,但是路径的字典序不同,“123”比“13”字典序要小,所以应当输出1-->2-->3.

更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/Programming/sjjg/

2.   用一个数组pre记录每一点的上一个结点。按照一般的单源最短路算法,在松弛时是有“小于”就直接松弛, 而这题还要判断“等于”的情况,在“等于”之时,这是要选择哪一个父结点所形成的路径字典序较小,就选择哪一个父结点。

所以,在“等于”之时,可以求出原先的路径, 再求出当前这个的路径,把路径转化成字符串,然后直接比较大小决定是否要换父结点。

3.  求路径的方法并转化为字符串的方法, 其实很简单,用一个3行的递归函数就解决了。

4. 本题学到的新东西:

之后在网上搜题解,发现还可以用Floyd算法来解决,很神奇,再次感叹Floyd算法的强大,自己也只理解了个皮毛。

代码:

1. SPFA

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;  

const int INF = 0x7fffffff;
const int VN  = 105;  

int n;
int w[VN][VN];
int charge[VN];
int d[VN];
int pre[VN];
bool inq[VN];
int pos=0;  

void init(){
    for(int i=0; i<=n; ++i){
        w[i][i] = INF;
        for(int j=i+1; j<=n; ++j)
            w[i][j]=w[j][i]=INF;
    }
}  

// 获得从开始点到当前点的路径,转化成字符串
void dfs(int u, char *str){
    if(u==-1)return;
    dfs(pre[u],str);
    str[pos++] = u+'0';
}  

bool cmp(int origin, int now){
    char str1[100], str2[100];  

    //1. 获取原来的路径
    pos=0;
    dfs(origin,str1);
    str1[pos] = '\0';  

    //2.获取当前点的路径
    pos=0;
    dfs(now, str2);
    str2[pos++] = origin+'0';
    str2[pos]   = '\0';  

    //3.比较是否比原来的字典序小
    if(strcmp(str1, str2)==1)return true;
    return false;
}  

void SPFA(int src){
    memset(inq, 0, sizeof(inq));
    memset(pre, -1, sizeof(pre));
    int i,j;
    for(i=1; i<=n; ++i) d[i]=INF;
    d[src] = 0;
    queue<int>q;
    q.push(src);
    while(!q.empty()){
        int u = q.front(); q.pop();
        inq[u] = false;
        for(int v=1; v<=n; ++v)if(w[u][v]!=INF){
            int tmp = d[u]+w[u][v]+charge[v];
            if(d[v] > tmp){
                d[v] = tmp;
                pre[v] = u;
                if(!inq[v]){
                    inq[v] = true;
                    q.push(v);
                }
            }
            else if(d[v] == tmp && cmp(v, u)){
                pre[v] = u;
            }
        }
    }
}
// 打印路径
void print_path(int u){
    if(pre[u]==-1){
        printf("%d",u);
        return;
    }
    print_path(pre[u]);
    printf("-->%d",u);
}
int main(){  

    int i,j,src,des;
    while(scanf("%d",&n),n){
        init();
        for(i=1; i<=n; ++i){
            for(j=1; j<=n; ++j){
                scanf("%d",&w[i][j]);
                if(w[i][j]==-1) w[i][j]=INF;
            }
        }
        for(i=1; i<=n; ++i)
            scanf("%d",&charge[i]);  

        while(scanf("%d%d",&src,&des)){
            if(src==-1&&des==-1) break;
            // 备份
            int tmp1=charge[src], tmp2=charge[des];
            charge[src]=0, charge[des]=0; // 起始点和终点Tax收费为0
            SPFA(src);
            printf("From %d to %d :\n",src,des);
            printf("Path: ");
            print_path(des);
            printf("\nTotal cost : %d\n\n", d[des]);
            // 恢复
            charge[src]=tmp1, charge[des]=tmp2;
        }  

    }
    return 0;
}

2. Floyd 记录路径

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;  

const int INF = 0x7fffffff;
const int VN  = 105;  

int n;
int w[VN][VN];
int path[VN][VN];
int charge[VN];  

void init(){
    for(int i=0; i<=n; ++i){
        for(int j=0; j<=n; ++j){
            if(i!=j)w[i][j]=INF;
            else w[i][j]=0;
            path[i][j] = j;  // path[i][j]表示点i到j经过的第一个点`
        }
    }
}  

void Floyd(){
    for(int k=1; k<=n; ++k)
    for(int i=1; i<=n; ++i)
    for(int j=1; j<=n; ++j)if(w[i][k]!=INF && w[k][j]!=INF){
        int tmp = w[i][k]+w[k][j]+charge[k];
        if(w[i][j] > tmp){
            w[i][j] = tmp;
            path[i][j] = path[i][k];
        }
        else if(w[i][j] == tmp && path[i][j]>path[i][k]){
            path[i][j] = path[i][k];
        }
    }
}     

int main(){  

    int i,j,src,des;
    while(scanf("%d",&n),n){
        init();
        for(i=1; i<=n; ++i){
            for(j=1; j<=n; ++j){
                scanf("%d",&w[i][j]);
                if(w[i][j]==-1) w[i][j]=INF;
            }
        }
        for(i=1; i<=n; ++i)
            scanf("%d",&charge[i]);  

        Floyd();
        while(scanf("%d%d",&src,&des)){
            if(src==-1&&des==-1) break;
            printf("From %d to %d :\n",src,des);
            printf("Path: ");
            int u = src;
            printf("%d",u);
            while(u != des){
                printf("-->%d",path[u][des]);
                u = path[u][des];
            }
            puts("");
            printf("Total cost : %d\n\n", w[src][des]);
        }  

    }
    return 0;
}

作者:csdn博客 shuangde800

以上是小编为您精心准备的的内容,在的博客、问答、公众号、人物、课程等栏目也有的相关内容,欢迎继续使用右上角搜索按钮进行搜索int
, 这题怎么做啊
, 求解决
, 字典数组
, 结点
, 路径
, 字典
, 一个
, 城市
, 字典序
求小于n
a1385、a1385充电器、a1385 a1443的区别、ho1385、a1385充电器真假对比,以便于您获取更多的相关知识。

时间: 2024-11-05 17:28:37

HDU 1385 Minimum Transport Cost:最短路,打印字典序路径的相关文章

hdu 1385 Minimum Transport Cost

点击打开链接hdu 1385 思路:最短路+SPFA+路径记录+路径字典序比较 分析: 1 题目要求的单源的最短路,所以可以选择任意一种单源最短路来求解 2 题目还要求在路径和相同情况下要字典序小的,那么就要在更新dis数组的时候进行更新路径,如果是dis[i]>tmp,那么直接更新:如果是dis[i] == tmp的情况下,那么就要求出star->i 和 star->x的路径进行比较,然后判断能否更新. 3 注意询问的时候可能问的是同一个点. 代码: #include<iostr

zoj 1456 Minimum Transport Cost 最短路

   书上把这放在了bellman,但我觉得用floyd应该更加好写些     注意一个坑人的地方,就是测试数据中有自己到自己,输出是单独的n,而不是n-->n /* author:jxy lang:C/C++ university:China,Xidian University **If you need to reprint,please indicate the source** */ #include <iostream> #include <cstdio> #inc

HDU 3339 In Action:最短路+背包

链接: http://acm.hdu.edu.cn/showproblem.php?pid=3339 题目: Problem Description Since 1945, when the first nuclear bomb was exploded by the Manhattan Project team in the US, the number of nuclear weapons have soared across the globe. Nowadays,the crazy bo

hdu 1394 Minimum Inversion Number

hdu 1394 的传送门 Problem Description The inversion number of a given number sequence a1, a2, -, an is the number of pairs (ai, aj) that satisfy i < j and ai > aj. For a given sequence of numbers a1, a2, -, an, if we move the first m >= 0 numbers to

最短路专题【完结】

第一题 hdu 1317 XYZZY 点击打开hdu 1317 思路: 1 题目的图是一个有向图,并且可能存在环.第一个点的能量值为100,边的权值利用能量大小,例如2点为-60,如果1->2那么value[1][2] = -602 题目明确指出如果是要win的话,那么必须是经过的每条边都要大于0.那么我们只要把那些经过松弛操作后的点大于0的入队即可,小于等于0的点肯定不会出现在最终的路径上.3 如果存在正环的话,那么就有能量值无限大,那么这个时候只要判断这个点能否到达n4 判断是否是有环还是五

POJ 1385

Minimum Transport Cost Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Submission(s): 4487    Accepted Submission(s): 1114 Problem Description These are N cities in Spring country. Between each pair of cities

路由器设置COST的注意事项

OSPF路由协议是一种典型的链路状态的路由协议,一般用于同一个路由域内,在这里,路由域是指一个自治系统,即AS,它是指一组通过统一的路由政策或路由协议互相交换路由信息的网络. 在这个AS中,所有的OSPF路由器都维护一个相同的描述这个AS结构的数据库,该数据库中存放的是路由域中相应链路的状态信息,OSPF路由器正是通过这个数据库计算出其OSPF路由表的. 一.我们在配置完各接口的IP和OSPF 协议,路由器配置成帧中继交换机的,这样更有利于我们更好地理解帧中继,注意:在路由器的接口中,可以定义接

Winform 打印PDF顺序混乱,获取打印队列

原文:Winform 打印PDF顺序混乱,获取打印队列 工作中PDF打印顺序混乱着实让我疼痛了好久,其实决绝方法非常简单,但没有想到这个点子的时候确实让我走了很多弯路 这里文章写出来并不是为了炫耀什么,只是觉得发现些好东西就分享出来而已,同时也做个记录,方便以后查找 开始正文 既然要解决打印顺序混乱,那么必须先要实现打印PDF功能,实现PDF打印的方法很多,网上随便一搜就可以找到,这里我贴上自己的打印方法,其实也是网上找到的,稍稍做了修改 Process proc = new Process()

.NET DateTime coding best practices

.NET DateTime coding best practicesAuthor:  Dan Rogers (danro), Microsoft Corporation January 9, 2004 SynopsisWriting programs that store, perform calculations and serialize time values using the .NET DateTime type requires an awareness of the differ