Fishmonger [SPOJ] 二维最短路

一句话题意:

一个图中,对于每一条边有两个权值:路费和时间,我们要找一条从源点出发到终点的路,在这条路的时间不超过给定时间的基础上,找到路费最少的路。


分析:

如果按照普通的最短路,会因为有一个时间的限制而找不到正确的解。
找不到正确的解的原因就是对于每个点只能存一个时间,然而我们可能在多个不同时间到达一个点,不一定哪个时间会得到答案,后来的可能会把原来的覆盖掉,覆盖掉的就可能是正确的解。
按照这个想法,我们可以对于每一个点,保存每一个时间到达的情况。也就是存花费的数组变成一个二维数组。
第一维表示第几个点,第二维表示在什么时间到达这个点。
cost[i][j] = x的意思为:在时间 j 到达点 i 的最小化费为 x 。
剩下的就是基本的最短路了。

另外,因为本题数据量略小,DFS暴力也能出来,但是需要剪一下枝。
下面附上两种做法的代码


AC代码:

  • 二维最短路
#include 

using namespace std;

const int inf = 0x3f3f3f3f;
const int maxv = 100;

int cnt, vertex, time_limit;
int cost[maxv][1010], map_cost[maxv][maxv], map_time[maxv][maxv];
bool vis[maxv][1010];

void spfa()
{
    queue int, int> > que;
    que.push(make_pair(0, 0));
    cost[0][0] = 0;
    while (!que.empty())
    {
        int cur_pos = que.front().first;
        int cur_time = que.front().second;
        que.pop();
        vis[cur_pos][cur_time] = false;
        for (int i = 0; i < vertex; i++)
        {
            if (cur_pos == i)
                continue;
            int to_time = cur_time + map_time[cur_pos][i];
            if (to_time > time_limit)//如果时间已经超出,则不需要往下继续跑
                continue;
            if (cost[cur_pos][cur_time] + map_cost[cur_pos][i] < cost[i][to_time])//最短路的松弛操作
            {                                                          
                //注意是从当前节点的当前时间到目的节点的目的时间
                cost[i][to_time] = cost[cur_pos][cur_time] + map_cost[cur_pos][i];
                if (!vis[i][to_time])
                {
                    que.push(make_pair(i, to_time));
                    vis[i][to_time] = true;
                }
            }
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    while (cin >> vertex >> time_limit && (vertex || time_limit))
    {
        memset(vis, 0, sizeof(vis));
        memset(cost, inf, sizeof(cost));
        for (int i = 0; i < vertex; i++)
            for (int j = 0; j < vertex; j++)
                cin >> map_time[i][j];
        for (int i = 0; i < vertex; i++)
            for (int j = 0; j < vertex; j++)
                cin >> map_cost[i][j];
        spfa();
        int ans_time, ans_cost = inf;
        //遍历目的节点的每一个时间,找到所有的时间里最少的花费并记录下来
        for (int i = 0; i <= 1000; i++)
        {
            if (ans_cost > cost[vertex - 1][i])
            {
                ans_cost = cost[vertex - 1][i];
                ans_time = i;
            }
        }
        cout << ans_cost << ' ' << ans_time << endl;
    }
    return 0;
}
  • DFS
#include 

using namespace std;

const int inf = 0x3f3f3f3f;
int toll[100][100], Time[100][100], vis[100];
int vertex, latestTime, ansToll = inf, ansTime = inf;

void DFS(int cur, int dis, int time)
{
    if (cur == vertex)//到达了节点,保存一下最小花费
    {
        if (dis < ansToll)
        {
            ansTime = time;
            ansToll = dis;
        }
        return;
    }
    for (int i = 1; i <= vertex; i++)
    {
        //注意这里需要加一个 "dis + toll[cur][i] <= ansToll"的剪枝
        //如果当前的花费已经超过了已经求出的答案的最小花费,那么没有必要继续往下跑
        if (dis + toll[cur][i] <= ansToll && time + Time[cur][i] <= latestTime && !vis[i])
        {
            vis[i] = true;
            DFS(i, dis + toll[cur][i], time + Time[cur][i]);
            vis[i] = false;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    while (cin >> vertex >> latestTime && (vertex || latestTime))
    {
        ansToll = inf;
        ansTime = inf;
        memset(vis, 0, sizeof(vis));
        for (int i = 1; i <= vertex; i++)
            for (int j = 1; j <= vertex; j++)
                cin >> Time[i][j];
        for (int i = 1; i <= vertex; i++)
            for (int j = 1; j <= vertex; j++)
                cin >> toll[i][j];
        vis[1] = true;
        DFS(1, 0, 0);
        vis[1] = false;
        cout << ansToll << ' ' << ansTime << endl;
    }
    return 0;
}

你可能感兴趣的:(最短路)