UCF Local Programming Contest 2017 F Multimodal Transport 【最短路+建图】

Description

New methods of shipping goods have transformed the transportation industry and helped usher in an era of global commerce.  Nowadays, someone can click a few buttons and have an item leave a factory on the other side of the world and show up at their doorstep the next day.  To help accomplish this, there are a number of modes of transport within the shipping industry.  The four most common are: air, boat, rail and truck.     

Transportation companies tend to keep the mode of transport consistent throughout a packages journey (route/path).  However, when customers are not very time sensitive, often times the cheapest way to move a package from one location to another is to use more than one mode of transport.  One has to be careful, though, as additional costs are incurred when switching between transport modes within a city on the package path.   (Switching transport mode refers to a package leaving a city in a different mode than it arrived at the city, e.g., the package arrived by air and leaves by truck.)   

A new startup, KnightShip, has asked for your help in figuring out the cheapest way to ship packages when switching between transportation modes is acceptable. 

Problem

Given the costs for various modes of transport between cities, and the cost of switching mode within a city, calculate the lowest cost to transport an item from an origin to a destination.  

Input

The first input line contains a positive integer, n, indicating the number of test cases to process.  Each test case will contain multiple input lines.  The first line of each test case will contain an integer, c (2 ≤ c ≤ 400), representing the number of cities within the transportation network.  Each of the following c input lines contains two values: a string (1 to 20 uppercase letters, inclusive), representing the name of a city and an integer (between 1 and 1000, inclusive), representing the cost of changing the transport mode within that city.  

The city information for a test case is followed by the route information for the test case.  There will be an input line containing one integer, r (1 ≤ r ≤ 40000), representing the number of route segments in the network.  This will be followed by a listing of all route segments, one per line.  Each route segment will contain four values: p, q, representing two cities from the previous list, m, representing the transport mode (one of four values AIR, SEA, RAIL, TRUCK) for that route segment, and an integer v (1 ≤ v ≤ 1000), representing the cost to ship a package between the two cities (either direction).  Note that there may be no route segments for a particular transport mode.  There will be no duplicate city pair within a given mode of transport, but different transport modes (even all four modes) can exist between the same two cities. 

The last input line for a test case contains two distinct cities o and d which represent the origin and destination cities for which we want the minimum cost to ship a package.  Cities o and d are guaranteed to have a path (of finite cost) that exists between them.  Any mode of transport can be used to leave city o and any mode can be used to reach city d (they don’t necessarily need to match).  The transport mode can change in the intermediate stages as well.  

Output

For each test case, output a single integer on a line by itself indicating the minimum cost to move a package from city o to city d.  

样例输入

2
4
ORLANDO 10
TAMPA 15
MIAMI 5
JACKSONVILLE 10
7
TAMPA JACKSONVILLE AIR 100
MIAMI TAMPA SEA 70
JACKSONVILLE MIAMI RAIL 45
ORLANDO JACKSONVILLE TRUCK 85
TAMPA ORLANDO RAIL 10
MIAMI JACKSONVILLE SEA 15
ORLANDO MIAMI TRUCK 15
JACKSONVILLE TAMPA
2
ORLANDO 15
TAMPA 10
3
ORLANDO TAMPA AIR 7
TAMPA ORLANDO TRUCK 3
ORLANDO TAMPA RAIL 19
ORLANDO TAMPA

样例输出

55
3

题目大意:

给定c座城市和4种交通方式,在每个城市切换交通方式需要一定的费用,另外给定一些城市两两之间存在的交通方式和该方式下运输所需的费用,求从起点到终点所需的最少费用。

分析:

如果没有城市内交通方式的切换,那么我们可以把城市当作点,城市之间运输的费用当作边的权值,只需要跑一边最短路就行。

对于城市内交通方式的切换,我们考虑把每个城市进行拆分,把一个城市拆分成4个点,每个点表示一种交通方式,那么城市内交通方式的切换费用就可以表示为这四个点两两之间边的权值。相应地,城市之间特定交通方式的运输费用也就可以表示为两个城市中对应交通方式表示的点之间的边的权值。

这样,我们就建立了一张无向图,只需要在这张图上跑一遍最短路即可。

要注意的是,题目中说起点可以以任意的交通方式出发,终点也可以以任意交通方式到达,那么就需要对起点城市按4种交通方式分别跑最短路,同时每次需要取到达终点城市的四种交通方式中费用最小的。

具体解释见代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define INF 0x3f3f3f3f
#define mst(a,num) memset(a,num,sizeof a)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
const ll mod = 1e9 + 7;
const int maxn = 400 + 5;

struct node{
	int nxt,w;
};

int c;
int vis[maxn*4];
ll dis[maxn*4];
vector<node> edge[maxn*4];
char str[maxn];
map<string,int> mp;

struct point{
    ll val,id;
    point(ll id,ll val):id(id),val(val) {}
    bool operator <(const point &x)const{ 
        return val>x.val;
    }
};
 
void dijkstra(int s){       //最短路采用Dijkstra
    memset(vis,0,sizeof(vis));
    for(int i=1; i<=4*c; i++)
        dis[i]=INF;
 
    priority_queue<point> q;
    q.push(point(s,0));
    vis[s]=1;
    dis[s]=0;
    while(!q.empty()){
        ll cur=q.top().id;
        q.pop();
        vis[cur]=1;
        for(int i=0; i < edge[cur].size() ; i++){
            ll id=edge[cur][i].nxt;
            ll cost=edge[cur][i].w;
            if(!vis[id]&&dis[id]>dis[cur]+cost){
            	dis[id]=dis[cur]+cost;
            	q.push(point(id,dis[id]));
            }
        }
    }
}

int main() {
    int cas;
    scanf("%d",&cas);
    while(cas--){
        int d;
        string s;
        scanf("%d",&c);
        rep(i,1,c*4)  edge[i].clear();
        mp.clear();
        rep(i,1,c){
            scanf("%s",str);
            s=str;
            mp[s]=i;
            scanf("%d",&d);
            node tmp;
            rep(j,0,3){                         //用i,i+c,i+2c,i+3c分别表示城市i中的AIR, SEA, RAIL, TRUCK四种交通方式
                rep(k,j+1,3){                   //四种交通方式两两之间连边,边的权值为切换交通方式的费用
                    tmp.nxt=i+k*c;
                    tmp.w=d;
                    edge[i+j*c].push_back(tmp);
                    tmp.nxt=i+j*c;
                    edge[i+k*c].push_back(tmp);
                }
            }
        }
        int r,u,v;
        scanf("%d",&r);
        rep(i,1,r){
            scanf("%s",str);
            s=str;
            u=mp[s];
            scanf("%s",str);
            s=str;
            v=mp[s];
            scanf("%s",str);
            scanf("%d",&d);
            node tmp;
            if(str[0]=='A'){                    //在两城市对应交通方式的点之间连边
                tmp.nxt=v;
                tmp.w=d;
                edge[u].push_back(tmp);
                tmp.nxt=u;
                edge[v].push_back(tmp);
            }
            else if(str[0]=='S'){
                tmp.nxt=v+c;
                tmp.w=d;
                edge[u+c].push_back(tmp);
                tmp.nxt=u+c;
                edge[v+c].push_back(tmp);
            }
            else if(str[0]=='R'){
                tmp.nxt=v+2*c;
                tmp.w=d;
                edge[u+2*c].push_back(tmp);
                tmp.nxt=u+2*c;
                edge[v+2*c].push_back(tmp);
            }
            else{
                tmp.nxt=v+3*c;
                tmp.w=d;
                edge[u+3*c].push_back(tmp);
                tmp.nxt=u+3*c;
                edge[v+3*c].push_back(tmp);
            }
        }
        scanf("%s",str);
        s=str;
        int st=mp[s];
        scanf("%s",str);
        s=str;
        int en=mp[s];
        ll ans=1e18;
        rep(i,0,3){                             //对起点的四种交通方式的点分别跑最短路
            dijkstra(st+i*c);                   
            rep(j,0,3){                         //取终点处四种交通方式的点的最小值
                ans=min(ans,dis[en+j*c]);
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}
发布了30 篇原创文章 · 获赞 5 · 访问量 900

猜你喜欢

转载自blog.csdn.net/qq_42840665/article/details/105460240