1. 程式人生 > >hdu 4370 0 or 1,最短路

hdu 4370 0 or 1,最短路

push i++ each algo algorithm 比較 所有 namespace 是不是

題目描述

給定n * n矩陣C ij(1 <= i,j <= n),我們要找到0或1的n * n矩陣X ij(1 <= i,j <= n)。
此外,X ij滿足以下條件:
1.X 12 + X 13 + ... X 1n = 1
2.X 1n + X 2n + ... X n-1n = 1
3.對於每個i(1 <i <n),滿足ΣXki(1 <= k <= n)=ΣXij(1 <= j <= n)。
例如,如果n = 4,我們可以得到以下等式:
X 12 + X 13 + X 14 = 1
X 14 + X 24 + X 34 = 1
X 12 + X 22 + X 32 + X 42 = X 21 + X 22 + X 23 + X 24

X 13 + X 23 + X 33 + X 43 = X 31 + X 32 + X 33 + X 34
現在,我們想知道你可以得到的最小ΣCij * X ij(1 <= i,j <= n)。
Input
The input consists of multiple test cases (less than 35 case).
For each test case ,the first line contains one integer n (1<n<=300).
The next n lines, for each lines, each of which contains n integers, illustrating the matrix C, The j-th integer on i-th line is Cij(0<=Cij<=100000).
Output
For each case, output the minimum of ∑C ij*X ij you can get.
Sample Input
4
1 2 4 10
2 0 1 1
2 2 0 5
6 3 1 2
Sample Output
3

題目分析

關鍵是要理解輸入的C是一個i到j的距離的一個矩陣。
X中滿足:
1.X 12+X 13+…X 1n=1
2.X 1n+X 2n+…X n-1n=1
3.for each i (1 < i < n) , satisfies ∑X ki (1<=k<=n)=∑X ij (1<=j<=n).
第一條就是1到其余個點的出度為1

第二條個點到n的只有一個,就是n的入讀為1
第三條其余各點出度入度相同。
叫你求乘積最小,於是便成為了最短路問題。從1到n,給定所有的距離,讓你求出最短路問題(X是任意調配,只要滿足三個條件就行,於是調配出最短路)

再來想象一下,一個圖,n個點中,1號點出度為1,n號點入度為1,其余個點出度等於入度。其實每個點都能到其余個點,只不過這條邊是由Xij控制,當其為1是這條邊就顯示出來了。要滿足這三個條件,然後求處,顯示出來的邊長總和最短。

所以,可能還不單單只有一個最短路(最短路必定能夠滿足起點出度為1,終點入度為1,其余個點入度等於出度等於1)。
還有一種情況,1號點滿足了出度為1,但它再來一個入度為1,同樣,n號點也滿足了入度為1,但是它再來一個出度為1。那麽這就是不是從1到n的最短路了,這成了,1號點經過一些點成了一個閉環,n號點經過剩下的那些點成了一個閉環。這也可能是最短的,要與第一種情況做個比較才知道。
比如,有5個點,假設第一種情況下最短路為1-2-3-4-5。第二種閉環下的情況為,1-2-3-1和5-4-5兩個閉環。顯然,這兩種情況都能滿足X的三種條件。所以最終問題就是找到最短路與閉環最短路下誰的路徑總和最短。

難題啊,還要多方面考慮呢。

采用SPFA算法。
關於SPFA,就是從起點開始,將與起點相連的點拉進隊列中。
然後開始操作這個隊列:不斷地出去隊首元素,如果dis[i]>dis[u]+cost[u][i],u為出去的隊首元素,dis為起點到點i的最短距離。就是不斷更新最短的距離,只要這個要出去的對手元素的點的最短距離加上它到達旁邊i的邊更小了,那麽就更新一下。
最終,隊列裏所有元素都會出去,空了,就說明個點的擴散已經好了,更新不了了,那麽最短距離就一定產生了。

代碼

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
#include<queue>

using namespace std;

const int INF = 0x3f3f3f3f;

int cost[305][305];
int dis[305];
int n;
bool v[305]; //判斷是否i點在隊列中
int q[305];

void spfa(int s) {
    queue<int> q;
    for (int i = 1; i <= n; i++) {
        if (i == s) {
            dis[i] = INF;
            v[i] = 0;
        }else {
            dis[i] = cost[s][i];
            v[i] = 1;
            q.push(i);
        }
    }

    while (!q.empty()) {
        int u = q.front();
        q.pop();
        v[u] = 0;
        for (int i = 1; i <= n; i++) {
            if (dis[i] > dis[u] + cost[u][i]) {
                dis[i] = dis[u] + cost[u][i];
                if (v[i] == 0) {
                    v[i] = 1;
                    q.push(i);
                }
            }
        }


    }

}

int main() {
    while (scanf("%d", &n) != EOF) {
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                scanf("%d", &cost[i][j]);

        spfa(1);
        int ans = dis[n];
        int c1 = dis[1];
        spfa(n);
        int cn = dis[n];

        printf("%d\n", min(ans, c1 + cn));
    }
    return 0;
}

hdu 4370 0 or 1,最短路