J 小雨坐地铁(分层最短路)

链接:https://ac.nowcoder.com/acm/contest/949/J
来源:牛客网

小雨所在的城市一共有 m 条地铁线,分别标号为 1 号线,2 号线,……,m 号线。整个城市一共有 n个车站,编号为 1n 。其中坐 i 号线需要花费 ai的价格,每坐一站就需要多花费 bi 的价格。i 号线有 ci 个车站,而且这 ci 个车站都已知,如果某一站有多条地铁线经过,则可以在这一站换乘到另一条地铁线,并且能多次换乘。现在小雨想从第 s 个车站坐地铁到第 t个车站,地铁等待时间忽略不计,求最少花费的价格,若不能到达输出 -1 。(地铁是双向的,所以 s可能大于 t

输入描述:

第一行输入四个正整数 n,m,s,t分别表示车站个数,地铁线数,起点站和终点站。
第二行到第 m+1 行,每行前三个数为 ai,bi,ci,分别表示坐 i 号线的价格,i 号线每坐一站多花的价格,i 号线车站个数。接下来 ci个数,表示 i 号线的每一个车站的编号,单调递增。

输出描述:

共一行,一个数表示最小花费,若不能到达输出 -1 
示例1

输入

5 2 1 4
2 2 3 1 3 5
2 1 4 2 3 4 5

输出

7

说明

坐 1 号线:花费 2;

13:花费 2;

换乘 2 号线:花费 2;

34:花费 1;

所以最小总花费为 7 。

备注:

1n1000,1m500,1s,tn

1ai,bi100,1cin,mi=1ci105

思路:每条地铁线路可以看做一层图,一层一层图之间正常建边即可。每层之间可能是相连的,怎么处理?
对应每个车站 设立一个虚点。只要每层的车站与对应的虚点连接即可。 连接方式是虚点连向车站的花费是上地铁的钱(或转地铁的钱)。
而车站连接虚点花费为0,这样达到中转的效果。


设立虚点的好处:不用根据层与层间连边,这样每层都要连,就要m*m*n条边,而设立虚点只要n*m*2。
计算也方便,直接从s的虚点可是找t的虚点的最短路就是结果。不设虚点,要对应每个车站s的地铁到每个车站t的地铁求最短路。

代码:
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<vector>
#include<queue>
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const int maxn=2100;
struct node{
    int u,v,w,next;
}e[maxn*maxn]; 
int head[maxn*maxn],n,m,s,t,cnt;
int a[maxn],b[maxn],d[maxn*maxn],vis[maxn*maxn];
void add(int u,int v,int w)
{
    e[cnt]={u,v,w,head[u]};
    head[u]=cnt++;
}

void spfa(int st)//spfa
{
    d[st]=0;
    queue<int> q;
    q.push(st);
    vis[st]=1;
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        vis[u]=0;
        for(int i=head[u];i!=-1;i=e[i].next)
        {
            int v=e[i].v;
            int w=e[i].w;
            if(d[v]>d[u]+w)
            {
                d[v]=d[u]+w;
                if(!vis[v])
                {
                    vis[v]=1;
                    q.push(v);
                }
            }
        } 
    }        
}

int main()
{
    int num,x,last;
    cnt=0;
    memset(head,-1,sizeof(head));
    memset(d,0x3f,sizeof(d));
    scanf("%d%d%d%d",&n,&m,&s,&t);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a[i],&b[i],&num);
        for(int j=1;j<=num;j++)
        {
            scanf("%d",&x);
            if(j!=1)
            {
                add((i-1)*n+x,(i-1)*n+last,b[i]);//同一条线车站相连 
                add((i-1)*n+last,(i-1)*n+x,b[i]);
            }
            add((i-1)*n+x,n*m+x,0);//与每个虚点相连 
            add(n*m+x,(i-1)*n+x,a[i]);
            last=x;//记录之前的车站 
        }
    }
    spfa(n*m+s);//最短路 
    if(d[n*m+t]<inf)
        printf("%d\n",d[n*m+t]);
    else
        printf("-1\n");
    return 0;
} 

猜你喜欢

转载自www.cnblogs.com/xiongtao/p/11183255.html
J