简体   繁体   中英

How exactly can I handle the following condition while applying dijkstra's algorithm to this?

So, I was solving the following question: http://www.spoj.com/problems/ROADS/en/

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.

Input

The input begins with the number t of test cases. Then t test cases follow. The first line of the each test case 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 <= ND is the destination city, 1 <= D <= NL 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.

Output

For each test case, output a single line 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, output -1.

Now, what I did was, I tried to use the djikstra's algorithm for this which is as follows:

Instead of only having a single node as the state, I take node and coins as one state and then apply dijkstra. length is the weight between the states. and I minimize the length without exceeding the total coins.

My code is as follows:

using namespace std;
#define ll long long
#define pb push_back
#define mp make_pair

class node
{
public:
    int vertex;
    int roadlength;
    int toll;
};

int dist[101][101]; // for storing roadlength
bool visited[101][10001];
int cost[101][101]; // for storing cost
int ans[101][10001]; // actual distance being stored here
void djikstra(int totalcoins, int n);

bool operator < (node a, node b)
{
    if (a.roadlength != b.roadlength)
        return a.roadlength < b.roadlength;
    else if (a.toll != b.toll)
        return a.toll < b.toll;
    return a.vertex < b.vertex;
}

int main (void)
{
    int a,b,c,d;
    int r,t,k,n,i,j;
    cin>>t;
    while (t != 0)
    {
        cin>>k>>n>>r;
        for (i = 1; i <= 101; i++)
            for (j = 1; j <= 101; j++)
                dist[i][j] = INT_MAX;

        for (i = 0; i <= n; i++)
            for (j = 0; j <= k; j++)
                ans[i][j] = INT_MAX;

        for ( i = 0; i <= n; i++ )
            for (j = 0; j <= k; j++ )
                visited[i][j] = false;

        for (i = 0; i < r; i++)
        {
            cin>>a>>b>>c>>d;
            if (a != b)
            {
                dist[a][b] = c;
                cost[a][b] = d;
            }
        }
        djikstra(k,n);
        int minlength = INT_MAX;
        for (i = 1; i <= k; i++)
        {
            if (ans[n][i] < minlength)
                minlength = ans[n][i];
        }
        if (minlength == INT_MAX)
            cout<<"-1\n";
        else
            cout<<minlength<<"\n";
        t--;
    }
    cout<<"\n";
    return 0;
}

void djikstra(int totalcoins, int n)
{
    set<node> myset;
    myset.insert((node){1,0,0});
    ans[1][0] = 0;
    while (!myset.empty())
    {
        auto it = myset.begin();
        myset.erase(it);
        int curvertex = it->vertex;
        int a = it->roadlength;
        int b = it->toll;
        if (visited[curvertex][b] == true)
            continue;
        else
        {
            visited[curvertex][b] = true;
            for (int i = 1; i <= n; i++)
            {
                if (dist[curvertex][i] != INT_MAX)
                {
                    int foo = b + cost[curvertex][i];
                    if (foo <= totalcoins)
                    {
                        if (ans[i][foo] >= ans[curvertex][b] + cost[curvertex][i])
                        {
                            ans[i][foo] = ans[curvertex][b] + cost[curvertex][i];
                            myset.insert((node){i,ans[i][foo],foo});
                        }
                    }
                }
            }
        }
    }
}

Now, I have two doubts:

  1. Firstly, my output is not coming correct for the first given test case of the question, ie

    Sample Input:

     2 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 0 4 4 1 4 5 2 1 2 1 0 2 3 1 1 3 4 1 0 Sample Output: 11 -1 

My output is coming out to be, 4 -1 which is wrong for the first test case. Where am I going wrong in this?

  1. How do I handle the condition of having multiple edges? That is, question mentions, Notice that different roads may have the same source and destination cities. How do I handle this condition?

The simple way to store the roads is as a vector of vectors. For each origin city, you want to have a vector of all roads leading from that city.

So when you are processing a discovered "best" path to a city, you would iterate through all roads from that city to see if they might be "best" paths to some other city.

As before you have two interacting definitions of "best" than cannot be simply combined into one definition. Shortest is more important, so the main definition of "best" is shortest considering cheapest only in case of ties. But you also need the alternate definition of "best" considering only cheapest.

As I suggested for the other problem, you can sort on the main definition of "best" so you always process paths that are better in that definition before paths that are worse. Then you need to track the best seen so far for the second definition of "best" such that you only prune paths from processing when they are not better in the second definition from what you already processed prioritized by the first definition.

I haven't read your code, however I can tell you the problem cannot be solved with an unmodified version of Dijkstra's algorithm.

The problem is at least as hard as the binary knapsack problem . How? The idea is to construct the knapsack problem within the stated problem. Since the knapsack problem is known to be not solvable within polynomial time, neither is the stated problem's. Since Dijkstra's algorithm is a polynomial algorithm, it therefore could not apply.

Consider a binary knapsack problem with a set of D many values X and a maximum value m = max(X) . Now construct the proposed problem as such:

Let there be D + 1 cities where city n is connected to city n + 1 by two roads. Let cities 1 through D uniquely correspond to a value v in X . Let only two roads from such a city n go only to city n + 1 , one costing v with distance m - v + 1 , and the other costing 0 with a distance of m + 1 .

In essence, "you get exactly what you pay for" -- for every coin you spend, your trip will be one unit of distance shorter.

This reframes the problem to be "what's the maximum Bob can spend by only spending money either no or one time on each toll?" And that's the same as the binary knapsack problem we started with.

Hence, if we solve the stated problem, we also can solve the binary knapsack problem, and therefore the stated problem cannot be any more "efficient" to solve than the binary knapsack problem -- with Dijkstra's algorithm is.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM