ZOJ - 1456 FLOYD路徑輸出

題目大意

有N個(gè)城市,城市之間只有最多一條運(yùn)輸路線,現(xiàn)在有一批貨要從一個(gè)城市到另一個(gè)城市,運(yùn)輸費(fèi)用分為兩部分,第一是運(yùn)輸路線的費(fèi)用,二是經(jīng)過一個(gè)城市所交的稅費(fèi)。求費(fèi)用的最小路徑。

樣例輸入

5
0 3 22 -1 4
3 0 5 -1 -1
22 5 0 9 20
-1 -1 9 0 4
4 -1 20 4 0
5 17 8 3 1
1 3
3 5
2 4
-1 -1
0

第一行是一個(gè)數(shù)字N代表N個(gè)城市,接下來N行表示第i個(gè)城市到第j個(gè)城市運(yùn)輸路線的費(fèi)用。緊接著一行是每個(gè)城市的稅。接下來的每對(duì)數(shù)字代表要求的起點(diǎn)城市,到終點(diǎn)城市。-1 和 -1 代表輸入結(jié)束。

樣例輸出

對(duì)于每對(duì)城市輸出

From 1 to 3 :
Path: 1-->5-->4-->3
Total cost : 21

From 3 to 5 :
Path: 3-->4-->5
Total cost : 16

From 2 to 4 :
Path: 2-->1-->5-->4
Total cost : 17

題目分析

這題不難,就是用FLOYD,但是輸出路徑的話是個(gè)問題。我嘗試著用書上的方法倒著輸出,也就是path數(shù)組存的是上一個(gè)點(diǎn)的位置。發(fā)現(xiàn)無論如何都要RE。然后在網(wǎng)上看到一個(gè)好辦法就是path數(shù)組存下一個(gè)點(diǎn)的位置。這樣寫起來也很簡單,而且直接性的表達(dá)了路徑 。

這題還有第二個(gè)問題,就是如果有多種選擇,則要按字典序最小的路徑輸出。
這個(gè)時(shí)候在FLOYD改變路徑的時(shí)候加上如下語句就搞定
if(A[i][j] == A[i][k] + A[k][j] + tax[k] && path[i][j] > path[i][k])
path[i][j] = path[i][k];
這樣就表示在同樣的長度下選擇字典序更小的點(diǎn)。

代碼入下

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<map>
#include<queue>
#include<vector>
#include<cmath>
#define LL long long
#define eps 1e-6
#define CLR(x) memset(x,0,sizeof(x))
using namespace std;
const int maxn = 133;
const int inf = 1 << 29;
int n;
int A[maxn][maxn] , path[maxn][maxn] ;
int tax[maxn];

void floyd(){
    for(int k = 1 ; k <= n ; k++){
        for(int i = 1 ; i <= n ; i++){
            for(int j = 1 ; j <= n ; j++){
                if( A[i][k] + A[k][j] + tax[k] < A[i][j] ){
                    A[i][j] = A[i][k] + A[k][j] + tax[k];
                    path[i][j] = path[i][k];
                }
                else if(A[i][k] + A[k][j] + tax[k] == A[i][j]){
                    if(path[i][j] > path[i][k]){
                        path[i][j] = path[i][k];
                    }
                }
            }
        }
    }
}

int main(){
    while(scanf("%d",&n)&& n){
        for(int i = 1 ; i <= n ; i++)
            for(int j = 1 ; j <= n ; j++){
                scanf("%d",&A[i][j]);
                path[i][j] = j;
                if(A[i][j] == -1){
                    A[i][j] = inf;
                }
            }
        for(int i = 1 ; i <= n ; i++){
            scanf("%d",&tax[i]);
        }
        floyd();
        while(1){
            int a , b;
            scanf("%d%d",&a,&b);
            if(a == -1) break;
            printf("From %d to %d :\n",a,b);
            printf("Path: %d",a);
            for(int i = a ; i != b ; i = path[i][b])
                printf("-->%d",path[i][b]);
            printf("\nTotal cost : %d\n\n",A[a][b]);
        }
    }
    return 0;
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • 背景 一年多以前我在知乎上答了有關(guān)LeetCode的問題, 分享了一些自己做題目的經(jīng)驗(yàn)。 張土汪:刷leetcod...
    土汪閱讀 12,771評(píng)論 0 33
  • Floyd 算法 簡介 Floyd 算法又稱為插點(diǎn)法,是一種利用動(dòng)態(tài)規(guī)劃的思想尋找給定的加權(quán)圖中多源點(diǎn)之間最短路徑...
    廖少少閱讀 8,669評(píng)論 0 1
  • 回溯算法 回溯法:也稱為試探法,它并不考慮問題規(guī)模的大小,而是從問題的最明顯的最小規(guī)模開始逐步求解出可能的答案,并...
    fredal閱讀 13,728評(píng)論 0 89
  • 還有一個(gè)月,日本的4月份新學(xué)年就要開始了,相信有不少同學(xué)從現(xiàn)在開始因?yàn)楦鞣N手續(xù)和申請,與教授和學(xué)校事務(wù)室的郵件來往...
    在日留學(xué)生活閱讀 3,191評(píng)論 0 3
  • 當(dāng)亮哥帶著穿警服的王警官來到李部長面前時(shí),李部長著實(shí)嚇了一跳。 “哎呦,這不是張經(jīng)理嗎?”李部長趕緊站起來,伸出雙...
    魯郡閱讀 214評(píng)論 0 2