2

I made this implementation for this problem : http://www.spoj.pl/problems/SHOP/


#include<iostream>
#include<stdio.h>
#include<queue>
#include<conio.h>
#include<string.h>
using namespace std;

struct node
{
    int x;
    int y;
    int time;
};
bool operator <(const node &s,const node &r)
{
    if(s.time>r.time)
    return true;
    else return false;
}
node beg,src,dest,tempa;
int b,a,temp;
int map[25][25];
bool vis[25][25];
int X[]={1,0,-1,0};
int Y[]={0,1,0,-1};


int djs_bfs(node src,node dest)
{
    int result=0;
    priority_queue<node>pq;
    pq.push(src);
    while(!pq.empty())
    {
        node top = pq.top();
        pq.pop();
        if(top.x==dest.x && top.y==dest.y) return result;
        if(top.x<0 || top.x>=a) continue;
        if(top.y<0 || top.y>=b) continue;
        if(vis[top.x][top.y]) continue;

        vis[top.x][top.y]=true;
        result+=map[top.x][top.y];
        for(int i=0;i<4;i++)
        {
            tempa.x=top.x+X[0];
            tempa.y=top.y+Y[0];
            tempa.time=map[top.x+X[0]][top.y+Y[0]];
            pq.push(tempa);
        }
    }
    return -1;
}

int main()
{
    memset(vis,false,sizeof(vis));
    scanf("%d %d",&a,&b);
    while(a != 0)
    {
        for(int i=0;i<a;i++)
            for(int j=0;j<b;j++)
            {
                scanf("%c",&temp);
                if(temp=='X') {map[i][j]=0;vis[i][j]=true;}
                if(temp=='S') {src.x=i;src.y=j;src.time=0;}
                if(temp=='D') {dest.x=i;dest.y=j;dest.time=0;}
                else map[i][j]=temp-'0';
            }
        cout<<djs_bfs(src,dest)<<endl;
        scanf("%d %d",&a,&b);
    }
    return 0;
    getch();
}

I don't know why my code doesn't generate the right answer for the testcases. If someone can help me improve the code, please do so :D

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
magiix
  • 1,711
  • 2
  • 13
  • 11
  • Do you mean it doesn't work on the sample input? Or is it failed to provide correct answers to real test cases? – Gant Feb 03 '10 at 16:23

3 Answers3

4

First of all, the graph parsing code is incorrect. The first line specifies width and height, where the width is the number of characters per line the height is the number of lines. Therefore, swap &a and &b in the first scanf, or swap the order of the nested for loops (but not both). Also, I had to add dummy scanf("%c", &dummy); calls at various places to filter out newlines. A simple dump, such as this, will help determine if your map was parsed correctly:

cout << "a=" << a << endl;
cout << "b=" << b << endl;
for (int i=0; i<a; i++) {
    for(int j=0; j<b; j++) {
        cout << (char)('0' + map[i][j]) << ",";
    }
    cout << endl;
}

Note: I also set map[i][j] to 0 for 'S' and 'D', also changing the repeated if statements into an if; else if; else chain. This makes the algorithm more robust, since you can generically add time from the source or destination.

Now, on to the algorithm itself....

Each loop of the algorithm increments result by the current map location weight. However, the algorithm is searching multiple paths simultaneously (i.e., the number of entries in the priority queue), and therefore result ends up being the sum of all processed node weights, not the current path weight. The current path weight is top.temp, and therefore you can eliminate the result variable and simply return top.temp when you reach the destination.

Also, as other answers noted, you need to use X[i] and Y[i] in your inner loop, otherwise you are only searching in one direction.

Now, because of the addition/subtraction from X[i] and Y[i], you will likely access map[][] out of range (-1 or 25). Therefore, I recommend moving the if guards to the inner for loop to guard against the out-of-range access. This also avoids filling the priority queue with illegal possibilities.

Here is my version of the algorithm, with minimal corrections, for reference:

priority_queue<node>pq;
pq.push(src);
while(!pq.empty())
{
    node top = pq.top();
    pq.pop();

    if(top.x==dest.x && top.y==dest.y) return top.time;
    if(vis[top.x][top.y]) continue;

    vis[top.x][top.y]=true;

    for(int i=0;i<4;i++)
    {
        tempa.x=top.x+X[i];
        tempa.y=top.y+Y[i];
        if(tempa.x<0 || tempa.x>=a) continue;
        if(tempa.y<0 || tempa.y>=b) continue;
        tempa.time=top.time + map[tempa.x][tempa.y];
        pq.push(tempa);
    }
}
return -1;

I hope this helps.

Jason Govig
  • 1,219
  • 8
  • 5
  • Thank you, i ll be trying to apply your ideas and hope it will work :D – magiix Feb 04 '10 at 07:58
  • I tried to upgrade the code but still i can't make it work for the problem , this is the link , can you check ?? Link : http://codeviewer.org/view/code:bc9 It doesn't even generate that it stored the input correctly :S – magiix Feb 05 '10 at 11:48
  • 1
    You are still reading newlines as part of your data. (See my comment in the answer about adding dummy `scanf` calls.) To fix that, add `getch()` calls after each `scanf` call that reads in `a` and `b`, as well as each iteration of the outer for loop (after the inner `for` loop). This means you'll need curly braces for the outer `for` loop, which is a good practice anyway. You can also error check it by asserting that the character read is a newline. – Jason Govig Feb 05 '10 at 18:32
  • Well , after i put scanf("%c", &dummy); after each scanf a b and in the outer loop the input was stored correctly , so i stored the input correctly but i can't understand what makes the code read these newlines ?? Is there some wrong about my code that makes it read these newlines ?? – magiix Feb 05 '10 at 23:29
  • 1
    Newlines are characters, just like any other character. Therefore, when you process the stream character-by-character, you will encounter the newlines. See also: http://stackoverflow.com/questions/1669821/scanf-skips-every-other-while-loop-in-c Try reading the stream line-by-line (or string-by-string), and it will likely be easier. E.g., `cin >> b >> a;` at the start, `string buffer; cin >> buffer;` in the outer loop, and `char temp = buffer[j]` in the inner loop, checking that `buffer.size() == b` of course. – Jason Govig Feb 06 '10 at 05:12
  • Thanks man , i understood the concept from the link you provided . Thanks a lot :D. – magiix Feb 06 '10 at 08:09
2

You're using X[0] and Y[0] instead of X[i] and Y[i] in that inner loop.

By the way, other than that your Dijkstra's is very inefficient. First, you're pushing nodes onto the queue even when they have already been visited, and secondly, you may have several of the same node in the queue, just with different times. Ultimately neither of these things effect the outcome, but you're changing the complexity.

Edit: Oh, tempa.time should equal top.time plus the edge weight, not just the edge weight.

Peter Alexander
  • 53,344
  • 14
  • 119
  • 168
2

Why do you have 0 indexes?

tempa.x=top.x+X[0];
tempa.y=top.y+Y[0];
tempa.time=map[top.x+X[0]][top.y+Y[0]];

Nitpick:

bool operator <(const node &s,const node &r)
{
    if(s.time>r.time)
    return true;
    else return false;
}

Isn't this more readable:

bool operator <(const node &s,const node &r)
{
    return (s.time>r.time);
}
Kornel Kisielewicz
  • 55,802
  • 15
  • 111
  • 149