传送门:牛客
题目描述:
题目暂略
输入:
5 2 1 4
2 2 3 1 3 5
2 1 4 2 3 4 5
输出:
7
一道分层图的经典题型,可以细细体会,这道题模拟出了经典的分层图题型
主要思路:
- 首先我们那道这道题应该不难想到最短路(这是显然的吧).大多数人应该都是卡在了建边的部分.每一条线路各自的边是好建的,不过是双向边而已.不好想到的是如何完成换线的操作.这个似乎很难完成了
- 此时我们仔细想一下我们的换线过程,不就是在地铁站上下车吗.也就是在地铁站下车是不花钱的,上车是花钱的,那么我们是不是能将我们的地铁站看成一个个图中的节点呢,也就是我们的不同地铁线路中有各自的节点,然后我们的地铁站也是一个个节点,然后我们是通过不同线路中的各个节点在不同地铁站中穿梭
- 也就是我们的不同地铁线建图并且对应的地铁编号都再与各自的地铁站继续连线.这样我们的地铁就可以下车(不花钱),到地铁站再由地铁站上车到其他线路了(花钱).并且为了方便起见,我们可以假定我们的每一条线路中的编号不再是 1 − > n 1->n 1−>n,而是 n ∗ i + u − > n ∗ i + v n*i+u->n*i+v n∗i+u−>n∗i+v,这样的话建图更加清楚明白.
如果还是不太明白的话,我就样例举个栗子吧:
最终建图情况如上,中间的12345是地铁站,上下分别是地铁线路
这种分层建图的算法就是我们的分层图了,接下来直接跑 d i j k s t r a dijkstra dijkstra即可
下面是具体的代码部分:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <string.h>
#include <stack>
#include <deque>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define root 1,n,1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
ll x=0,w=1;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
return x*w;
}
#define maxn 1000000
#define ll_maxn 0x3f3f3f3f3f3f3f3f
const double eps=1e-8;
struct Node{
int v,w;
};
struct heapnode{
int u,d;
bool operator<(const heapnode &rhs) const {
return d>rhs.d;
}
};
int dis[maxn],vis[maxn];
vector<Node>edge[maxn];
int n,m;
void dij(int S) {
for(int i=1;i<=n*(m+2);i++) dis[i]=inf;
dis[S]=0;
priority_queue<heapnode>q;
q.push({S,0});
while(!q.empty()) {
heapnode f=q.top();q.pop();
int u=f.u;
if(vis[u]) continue;
vis[u]=1;
for(int i=0;i<edge[u].size();i++) {
int v=edge[u][i].v;
if(dis[v]>dis[u]+edge[u][i].w) {
dis[v]=dis[u]+edge[u][i].w;
q.push({v,dis[v]});
}
}
}
}
int s,t;
int main() {
n=read();m=read();s=read();t=read();
for(int i=1;i<=m;i++) {
int ai=read(),bi=read(),ci=read();
int U=read();int V;
edge[n*i+U].push_back({U,0});
edge[U].push_back({n*i+U,ai});
for(int j=2;j<=ci;j++) {
V=read();
edge[U+n*i].push_back({V+n*i,bi});
edge[V+n*i].push_back({U+n*i,bi});
edge[n*i+V].push_back({V,0});
edge[V].push_back({n*i+V,ai});
U=V;
}
}
dij(s);
if(dis[t]==inf) printf("-1\n");
else cout<<dis[t]<<endl;
return 0;
}