【深搜題目】POJ:1724

題目鏈接http://poj.org/problem?id=1724

題意:    N個城市,編號1到N。城市間有R條單向道路。 每條道路連接兩個城市,有長度和過路費兩個屬性。 Bob只有K塊錢,他想從城市1走到城市N。問最短共需要走多長的路。如果到不了N ,輸出-1

    2<=N<=100 

    0<=K<=10000

     1<=R<=10000 每條路的長度 L, 1 <= L <= 100 每條路的過路費T , 0 <= T <= 100

輸入:

K

N

R

s1 e1 L1 T1

s1 e2 L2 T2

...

sR eR LR TR

s e是路起點和終點

輸出:最短路的長度。 

樣例輸入:

5
6
7
1 2 2 3
2 4 3 3
3 4 2 4
1 3 4 1
4 6 2 1
3 5 2 0
5 4 3 2

 樣例輸出:

11

解題思路

從城市 1開始深度優先遍歷整個圖,找到所有能到達 N 的走法,選一個最優的。

最優性剪枝:

1) 如果當前已經找到的最優路徑長度爲L ,那麼在繼續搜索的過程中,總長度已經大於等於L的走法,就可以直接放棄,不用走到底了

另一種通用的最優性剪枝思想 ---保存中間計算結果用於最優性剪枝:

2) 如果到達某個狀態A時,發現前面曾經也到達過A,且前面那次到達A所花代價更少,則剪枝。這要求保存到達狀態A的到目前爲止的最少代價。

用midL[k][m] 表示:走到城市k時總過路費爲m的條件下,最優路徑的長度。若在後續的搜索中,再次走到k時,如果總路費恰好爲m,且此時的路徑長度已經超過midL[k][m],則不必再走下去了。

#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
struct Road
{
    int d,L,t;
};
int N,K,R;
vector < vector <Road> > G(110);//用二維數組表示臨界表,G[s]表示和s鄰接的路
int minLen;//全局變量,記錄最短的路徑長度
int totalCost;//當前狀態的花費
int totalLen;//當前狀態的長度
int visited[110];
int minL[110][10010];//minL[i][j]的意義是當到達i點是花費爲j時的最短路徑
void Dfs(int s)
{
    if(s==N)
    {
        minLen=min(minLen,totalLen);
        return ;
    }
    int len=G[s].size();
    for(int i=0;i<len;i++)//枚舉和s相鄰接額情況
    {
        Road r=G[s][i];
        if(!visited[r.d])//如果沒有被走過
        {
            /*下面三個if語句是三條剪枝條件*/
            if(totalCost+r.t>K)//如果當前花銷大於K了
                continue;
            if(totalLen+r.L>=minLen)//如果當前的路徑已經超過了已存在的最短路徑,那就沒必要往後dfs了
                continue;
            //如果存在兩種方式都到達同一點並且花銷相同,但是如果當前的長度大於另一種方式的長度,則continue
            if(totalLen+r.L>minL[r.d][totalCost+r.t])
                continue;
            minL[r.d][totalCost+r.t]=totalLen+r.L;
            visited[r.d]=1;
            totalCost+=r.t;
            totalLen+=r.L;
            Dfs(r.d);
            visited[r.d]=0;//因爲可能存在多種方式的dfs的路徑,所以每次dfs之後都要還原到之前的狀態
            totalCost-=r.t;
            totalLen-=r.L;
        }

    }
}
int main()
{

    cin>>K>>N>>R;
    for(int i=0;i<R;i++)
    {
        int s;
        Road r;
        cin>>s;
        cin>>r.d>>r.L>>r.t;
        G[s].push_back(r);
    }
    totalCost=0;
    totalLen=0;
    minLen=1<<30;//無窮大
    memset(visited,0,sizeof(visited));
    for(int i=1;i<=N;i++)
        for(int j=0;j<10010;j++)
            minL[i][j]=1<<30;
    visited[1]=1;
    Dfs(1);
    if(minLen<(1<<30))
        cout<<minLen<<endl;
    else
        cout<<-1<<endl;

    return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章