PAT 1030 Travel Plan (30)

来源:互联网 发布:2016淘宝联盟使用教程 编辑:程序博客网 时间:2024/06/05 22:33

A traveler's map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (<=500) is the number of cities (and hence the cities are numbered from 0 to N-1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:

For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

Sample Input
4 5 0 30 1 1 201 3 2 300 3 4 100 2 2 202 3 1 20

Sample Output

0 2 3 3 40
Hint:

先用Djikstra算出最短路径,纪录下相同的最短路径,再回溯计算花费最少的路径。

其实不用回溯,直接在比较最短路径的时候比较花费最少就可以了

代码如下:

#include<iostream>#include<queue>#include<algorithm>#include<functional>#include<cstdio>using namespace std;const int MAXV = 1000;//最大顶点数const int INF = 0x7fffffff;typedef pair<int, int> P;//first是最短距离,second是顶点的编号(这是不仅仅是指最短距离,也指最小花费)struct edge{    int to;    int dis;    int cost;};//采用邻接表表示,所以这样计算int V;vector<edge> G[MAXV];//图的邻接表表示法int d[MAXV];//s到各个点的最短距离,距离数组int pre[MAXV];//最短路中的上一条边,路径数组int cost[MAXV];//花费数组bool mark[MAXV];//判断是否属于K集合void init(int n)//初始化{    for (int i = 0; i <=n; i++)    {        G[i].clear();    }}void dijkstra(int s){    //通过指定greater<P>参数,堆按照first从小到大的顺序取出值    priority_queue<P,vector<P>,greater<P> > que;    fill(d, d + V, INF);    fill(pre, pre+V, -1);    fill(mark, mark + V, false);        d[s] = 0;    que.push(P(0,s));    while (!que.empty())    {        P p = que.top();        que.pop();        int v = p.second;        mark[v] = true;        cost[s] = 0;        for (int i = 0; i < G[v].size(); i++)        {            edge e = G[v][i];            int t = e.to;            if (mark[t])//顶点已经在集合K中                continue;            //比较大小时,将距离相同但花费更短也作为更新的条件之一            if (d[t]>d[v] + e.dis || (d[t] == d[v] + e.dis&&cost[t] > cost[v] + e.cost))            {                d[t] = d[v] + e.dis;                cost[t] = cost[v] + e.cost;                pre[t] = v;                que.push(P(d[t], t));            }        }    }}vector<int> get_path(int t)//到顶点t的最短路{    vector<int> path;    for (; t != -1; t = pre[t])    {        path.push_back(t);    }    reverse(path.begin(),path.end());    return path;}int main(){#ifdef ONLINE_JUDGE#else    freopen("D:\\in.txt", "r", stdin);    freopen("D:\\out.txt", "w", stdout);#endif    int n(0), m(0);    int S(0), T(0);//起点,终点    while (scanf("%d%d%d%d", &n, &m,&S,&T) != EOF)    {        V = n;        init(V);        while (m--)        {            int a(0), b(0), c(0), cost(0);            scanf("%d%d%d%d",&a,&b,&c,&cost);            edge e;            e.to = b;            e.cost = cost;            e.dis = c;            G[a].push_back(e);            e.to = a;            G[b].push_back(e);        }        dijkstra(S);        vector<int> path = get_path(T);        vector<int>::iterator it;        for (it = path.begin(); it != path.end(); it++)        {            printf("%d ", (*it));        }        printf("%d %d\n", d[T], cost[T]);    }    return 0;}

另外一种写法:

#include <iostream> #include <vector> #include <algorithm> #include <fstream> using namespace std;struct node{    int index;    int curDist;    vector<node> preCity;//当前结点的前一个结点,可能有重复路径,所以用vector存储前一个结点的所有值    node(int c, int d) : index(c), curDist(d) {}};const int MAXINT = 0x7fffffff;int n, m,d,s;vector<vector<int>> dist;vector<vector<int>> cost;//图中两个结点之间的花费vector<node> v;//图中所有结点的集合vector<node> q;//已求得最短路径的集合vector<int> result;int totalCost = MAXINT;bool cmp(const node &n1, const node &n2){    return n1.curDist > n2.curDist;}bool cmp1(const node &n1, const node &n2){    return n1.index < n2.index;}void Dijkstra(){    for (int i = 0; i < n; i++)        v.push_back(node(i, MAXINT));    v[s].curDist = 0;    while (!v.empty())    {        make_heap(v.begin(), v.end(), cmp);//把当前路径最小的放到堆顶        pop_heap(v.begin(), v.end(), cmp);//把当前路径最小的放到vector的末尾        node n = v.back();        v.pop_back();        for (int i = 0; i < v.size(); i++)//结点n加入已求得最短路径的集合后,更新所有结点(加入一个,全部更新一次)        {            if (dist[n.index][v[i].index] != -1)//n和v[i]都是图中的结点,n到v[i]间有路径            {                int now = dist[n.index][v[i].index] + n.curDist;                if (now < v[i].curDist)                {                    v[i].curDist = now;                    v[i].preCity.clear();                    v[i].preCity.push_back(n);                }                else if (now == v[i].curDist)//这一步很关键                    v[i].preCity.push_back(n);            }        }        q.push_back(n);//n为图中已求得最短路径的结点    }}void getPath(int index, int curCost, vector<int> &seq)//求得最短路径,相当强悍{    if (q[index].index == s)    {        if (curCost < totalCost)//求得结果一次,保存一次,如果有cost更小的路径,则更新        {            totalCost = curCost;            result = seq;        }    }    else    {        for (int i = 0; i < q[index].preCity.size(); i++)//回溯法求得有多个最短路径时的最短花费        {            seq.push_back(q[index].preCity[i].index);            curCost += cost[index][q[index].preCity[i].index];            getPath(q[index].preCity[i].index, curCost, seq);//典型的回溯法,上下对称            curCost -= cost[index][q[index].preCity[i].index];            seq.pop_back();        }    }}int main(){#ifdef ONLINE_JUDGE#else    freopen("D:\\in.txt", "r", stdin);    freopen("D:\\out.txt", "w", stdout);#endif    cin >> n >> m >> s >> d;    int i = 0;    dist = vector<vector<int>>(n, vector<int>(n, -1));    cost = vector<vector<int>>(n, vector<int>(n, -1));    int t1, t2, t3, t4;    while (i < m)    {        cin >> t1 >> t2 >> t3 >> t4;        dist[t1][t2] = dist[t2][t1] = t3;        cost[t1][t2] = cost[t2][t1] = t4;        i++;    }    Dijkstra();    sort(q.begin(), q.end(), cmp1);    vector<int> tmp;    getPath(d, 0, tmp);//不断地沿着终点找到起点    //不断沿着preCity走到s,这样得到的是按照t到s的顺序,所以要反向输出    for (vector<int>::reverse_iterator rit = result.rbegin(); rit != result.rend(); rit++)        cout << *rit << " ";    cout << d << " " << q[d].curDist << " " << totalCost << endl;}

代码如下(稍加修改):

#include<iostream>#include<vector>#include<algorithm>#include<fstream>#include<iterator>#include<utility>using namespace std;const int MAXINT = 0x7fffffff;const int MAXV = 501;int totalCost = MAXINT;//总花费struct node{    int index;    int curDist;//此结点距起始结点的距离    vector<node> preCity;//路径上当前结点的前一个结点,当有不同的路径,距离相同时,均保存下来    node(int i, int c) :index(i), curDist(c){};};vector<node> v;//图中的所有结点vector<node> p;//保存已求得最短路径的结点vector<vector<int> > dist;//图中两个结点的距离vector<vector<int> > cost;//图中两个结点的花费vector<int> result;//最短路径最短花费序列bool mycmp(const node& a, const node& b){    return a.curDist > b.curDist;}bool mycmp1(const node& a, const node& b){    return a.index < b.index;}int num,m,s,d;//总结点个数void dijkstra(){    for (int i = 0; i < num; i++)    {        v.push_back(node(i, MAXINT));//初始化    }    v[s].curDist = 0;    while (!v.empty())    {        make_heap(v.begin(), v.end(), mycmp);        pop_heap(v.begin(), v.end(),mycmp);        node n = v.back();        v.pop_back();        for (int i = 0; i <v.size(); i++)//更新所有结点        {            if (dist[n.index][v[i].index] != -1)            {                int now = dist[n.index][v[i].index] + n.curDist;                if (now < v[i].curDist)                {                    v[i].curDist = now;                    v[i].preCity.clear();                    v[i].preCity.push_back(n);                }                else if (now == v[i].curDist)//重复路径                {                    v[i].preCity.push_back(n);                }            }        }        p.push_back(n);//保存已求得最短径的结点    }}void getPath(node d, int curCost, vector<int>& seq){    if (d.index == s)    {        if (curCost < totalCost)        {            totalCost = curCost;            result = seq;        }    }    else    {        for (int i = 0; i < d.preCity.size(); i++)        {            curCost += cost[d.index][d.preCity[i].index];            seq.push_back(d.preCity[i].index);            getPath(d.preCity[i], curCost, seq);            curCost -= cost[d.index][d.preCity[i].index];            seq.pop_back();        }    }}int main(){#ifdef ONLINE_JUDGE#else    freopen("D:\\in.txt", "r", stdin);    freopen("D:\\out.txt", "w", stdout);#endif    cin >> num >> m >> s >> d;    int c1, c2, dis, c;    dist = vector<vector<int> >(num, vector<int>(num, -1));    cost = vector<vector<int> >(num, vector<int>(num, -1));    while (m--)    {        cin >> c1 >> c2 >> dis >> c;        dist[c1][c2] = dist[c2][c1] = dis;        cost[c1][c2] = cost[c2][c1] = c;    }    dijkstra();    vector<int> tmp;    sort(p.begin(), p.end(), mycmp1);//方便下面求路径时利用    getPath(p[d], 0, tmp);    for (vector<int>::reverse_iterator rit = result.rbegin(); rit != result.rend(); rit++)    {        cout<< (*rit)<<" ";    }    cout <<d<<" "<< p[d].curDist << " " << totalCost << endl;    return 0;}



0 0
原创粉丝点击