深搜最短路徑+剪枝——POJ1724:ROADS

POJ1724:ROADS


描述:

N cities named with numbers 1 … N are connected with one-way roads. Each road has two parameters associated with it : the road length and the toll that needs to be paid for the road (expressed in the number of coins).
Bob and Alice used to live in the city 1. After noticing that Alice was cheating in the card game they liked to play, Bob broke up with her and decided to move away - to the city N. He wants to get there as quickly as possible, but he is short on cash.

We want to help Bob to find the shortest path from the city 1 to the city N that he can afford with the amount of money he has.

輸入:
The first line of the input contains the integer K, 0 <= K <= 10000, maximum number of coins that Bob can spend on his way.
The second line contains the integer N, 2 <= N <= 100, the total number of cities.

The third line contains the integer R, 1 <= R <= 10000, the total number of roads.

Each of the following R lines describes one road by specifying integers S, D, L and T separated by single blank characters :

S is the source city, 1 <= S <= N
D is the destination city, 1 <= D <= N
L is the road length, 1 <= L <= 100
T is the toll (expressed in the number of coins), 0 <= T <=100

Notice that different roads may have the same source and destination cities.

輸出:
The first and the only line of the output should contain the total length of the shortest path from the city 1 to the city N whose total toll is less than or equal K coins.
If such path does not exist, only number -1 should be written to the output.

樣例輸入:

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


題目大概意思:

有N個城市,編號從1到N。城市間有R條單向的通路。每條通路是連接兩個城市,每條路有長度和過路費這樣兩個屬性。現在我們有K塊錢,讓我們找從1能夠到達N的最短路徑的長度,如果找不到輸出-1。

範圍:
2 <= N <= 100 (城市數)
0 <= K <= 10000 (擁有的錢)

1 <= R <= 10000 (道路數)

1 <= L <= 100 (每條路的長度)

0 <= T <= 100 (每條路的路費)


大概思路:

  • 首先我們知道這是一個尋找最短路徑的問題,用深搜做的話,是試圖找到所有能夠到達終點的路,然後 得到最短的一條路徑。

  • 然後具體到這道題還有路費這個問題,這是判斷是否能夠到達終點的一個條件。

  • 然後我們可以用一個鄰接表來存儲各個路的屬性,以及路與路之間的連接關係。用二維vector可方便實現。

  • 然後因爲用深搜找最短路徑其實是複雜度是大約指數級別的,那麼就很大可能會用到剪枝,剪枝又包括最優性剪枝和可行性剪枝。可行性剪枝就是說要走某一步時,我們判斷根據條件能否走那一步,比如這道題的錢的限制,我們就需要判斷我們的錢是否夠走那個點。然後是最優性剪枝,就是說我們達到某個點時,發現之前達到過此處並且更優。具體到這道題就是,當我們將要走一個點a,但是發現走a點的路徑的長度已經是比我們之前得出的最短路徑的長度要長了,那麼我們就沒有必要走下去了。其次,還有一個最優性剪枝就是當我們發現之前也達到過a點並且花費的錢都是一樣的,但是這次去a點的路徑長度更長,花相同的錢但是長度卻更長,那也沒有必要進行下去了。


AC代碼

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

struct Rode
{
    int d,l,t; //表示終點、長度、路費,不需要起點因爲起點是vector的行號 
}; 

int K,N,R;       //表示錢,城市數,道路數 
vector<vector<struct Rode > > map(110);
int visit[110];
int minLen = 1 << 30;      //最短路徑的長度 
int len,cost;              //當前路徑長度,花費 

int temp[110][10010];      //當花費多少錢走到哪個點的時候的路徑長度 

void dfs(int i)
{
    //邊界條件
    if(i == N) 
    {
        if(minLen > len)
            minLen = len;  //選擇是否更新最短長度 
        return ;    
    } 

    //循環所有直接連接的點
    int size = map[i].size();
    for(int j = 0; j < size; j ++)
    {
        Rode rode = map[i][j];

        //走過了
        if(visit[rode.d] != 0)
            continue;

        //可行性剪枝 
        if(cost + rode.t > K) 
            continue;

        //最優性剪枝
        if(len + rode.l > minLen)
            continue;

        if(len + rode.l > temp[rode.d][cost+ rode.t])
            continue;

        //嘗試走rode.d 
        temp[rode.d][cost + rode.t] = len + rode.l; 
        len += rode.l;
        cost += rode.t;
        visit[rode.d] == 1;

        dfs(rode.d);

        //回到這裏時,應該還原 這一步不走rode.d 
        len -=rode.l;
        cost -=rode.t;
        visit[rode.d] == 0; 
    } 

}

int main()
{
    scanf("%d %d %d",&K,&N,&R);

    for(int i = 0 ; i < R; i ++ )
    {
        Rode rode;
        int s;
        scanf("%d %d %d %d",&s,&rode.d,&rode.l,&rode.t);
        if(s!=rode.d)
        {
            map[s].push_back(rode);  //s爲地點,就在vector的s行號 
        }
    } 

    memset(visit,0,sizeof(visit));
    for(int i = 0; i< 110; i++)
        for(int j = 0; j < 10010; j ++)
            temp[i][j] = 1 << 30;


    visit[1] = 1;          //城市1已經走過
    len = 0;cost = 0;

    dfs(1);

    if(minLen == 1 << 30)
        printf("-1\n");

    else 
        printf("%d\n",minLen);

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