[Rudolf and Subway]

Rudolf and Subway

题目大意

给定一个\(n\)个点,\(m\)条边的无向图,第\(i\)条边表示\(x,y\)\(z\)号线的相邻站点,问\(s\)\(t\)最少需要换乘多少次

做法

用分层图,对于任意一条线路,让他们单独分为一层,如果一个点既在\(1\)号线又在\(2\)号线,那么它应该处于两个图层中,举个例子

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

在这个例子中显然\(1,2,3,4\)可以在一个图层中,同时\(1,3\)又可以在第二个图层中,分层的目的是为了,如果它需要去另一个图层,说明他一定要换乘(当前节点跳到另一个图层的当前节点不算),那么可以多创造一些'分身',来表示多个图层中都包含某个点,建边不按原来的建,而是首先要自己向自己的所有分身去建边保证可以由这个点换乘到其他图层中去,然后每个图层之间点,按照原来的关系去建边,然后令自己到分身长度为0,图层之间建边长度为0,由分身到本体的长度为1,最后跑最短路即可。

洛谷CF1941G

#include <map>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
typedef long long LL;
using namespace std;
const int maxn = 2e5+6,inf = 1e9;
int T,n,m,cnt,head[maxn*3],dis[maxn*3];
bool vis[maxn*3];
struct qwq{
	int to,len,next;
}edge[maxn*6];
struct node{
	int id,dist;
	bool operator < (const node &x)const
	{
		return dist > x.dist;
	}
};
priority_queue <node> q;
struct p{
	int fi,se;
	bool operator < (const p &x)const
	{
		return fi == x.fi ? se < x.se : fi < x.fi;
	}
};
map <p,int> mp;

inline void add(int u,int v,int w)
{
	cnt ++;
	edge[cnt].to = v;
	edge[cnt].len = w;
	edge[cnt].next = head[u];
	head[u] = cnt;
	return ;
}

int main()
{
	scanf("%d",&T);
	while(T --)
	{
		cnt = 0; mp.clear();
		scanf("%d%d",&n,&m);//n 2e5 m 2e5
		for(int i=1;i<=m;i++)
		{
	        int x,y,z,nx,ny;
	        scanf("%d%d%d",&x,&y,&z);
	        if(!mp[{x,z}])
			{
	            mp[{x,z}] = ++n;
	            nx = n;
	            add(nx,x,1);
	            add(x,nx,0);
	        }
			else nx = mp[{x,z}];
	        if(!mp[{y,z}])
			{
	            mp[{y,z}] = ++n;
	            ny = n;
	            add(ny,y,1);
	            add(y,ny,0);
	        }
			else ny = mp[{y,z}];
	        add(nx,ny,0);
	        add(ny,nx,0);
	    }
	    //n + m * 2 = 6e5
	    //cnt : 6 * m = 12e5
		for(int i=1;i<=n;i++)
		{
			dis[i] = inf;
			vis[i] = 0;
		}
		int b,e;
		scanf("%d%d",&b,&e);
		dis[b] = 0;
		q.push((node){b,0});
		while (!q.empty())
		{
	        int u = q.top().id; q.pop();
	        if(vis[u]) continue;
	        vis[u] = 1;
	        for(int i=head[u];i;i=edge[i].next)
	        {
	        	int v = edge[i].to;
	        	if(dis[v] > dis[u] + edge[i].len)
	        	{
	        		dis[v] = dis[u] + edge[i].len;
	        		q.push((node){v,dis[v]});
				}
			}
	    }
		for(int i=1;i<=n;i++) head[i] = 0; 
		printf("%d\n",dis[e]);
	}
	return 0;
}
/*
1
4 4
1 2 43
1 3 34
4 3 43
2 3 43
1 1
*/
posted @ 2024-04-05 17:30  风丨铃  阅读(1)  评论(0编辑  收藏  举报