【洛谷】P1629 邮递员送信 Dijkstra

P1629 邮递员送信 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define ll long long
#define IOS ios::sync_with_stdio(0),cin.tie(0),cout.tie(0)
const int N=1e3+10;
struct node{
	int x,y;
	bool operator<(const node&x)const{
		return x.y<y;
	}
};
vector<node>a[N*2];
int res[N*2];
bool st[N*2];
int n,m;
priority_queue<node>q;
void dijkstra(int x)
{
	//memset(res,0x3f,sizeof res);
	res[x]=0;
	q.push({x,0});
	while(q.size())
	{
		auto t=q.top();
		q.pop();
		int ver=t.x;
		if(st[ver]) continue;
		st[ver]=true;
		for(auto &i:a[ver])
		{
			int x=i.x,y=i.y;
			if(res[x]>res[ver]+y)
			{
				res[x]=res[ver]+y;
				q.push({x,res[x]});
			}
		}
	}
}
int main(){
	IOS;
	memset(res,0x3f,sizeof res);
	cin>>n>>m;
	while(m--)
	{
		int x,y,z;
		cin>>x>>y>>z;
		a[x].push_back({y,z});
		a[y+n].push_back({x+n,z});
	}
	dijkstra(1);
	dijkstra(1+n);
	ll sum=0;
	for(int i=1;i<=n;i++)
		sum+=res[i];
	
	for(int i=1+n;i<=n+n;i++)
		sum+=res[i];
	cout<<sum;
	return 0;
}

这个题大眼一看很简单那不就是Dijkstra嘛,但是仔细看看就会发现一点猫腻

仔细读题不难发现题意是让求从1到所有点的最短路径和,再加上所有点到1的最短路径和,很像Floyd。

但是!!!这个数据跑Floyd必然TLE,所以大暴力dijksra也肯定是不行的

那么就需要换一种思路

看一下思路图

假如说现在1到2之后需要从2回到1,首先它并不是一个双向图,所以他只能走其他路径回到1,从图上可以看出他必须要经过5再回到1,那么2到1的最短路径就相当于2到5到1,那么是不是变相的说就是1到5再到2呢?

没错,那么此时我们画一个反向的路径,就是让他们同时指向相反的,就是相当于反着可以走了,这样再从1跑一边Dijkstra,

首先Dijkstra是更新的从起点到每个点的最短路径,那么如果用反向图跑Dijkstra是不是相当于通过另一种方式计算了所有点到1的最短路径。

当然我们在存图的时候肯定不能直接反向存,那么就会有让图变成无向图,不仅不符合题意,而且还计算不出答案

聪明的人已经想出来了,这个题是跑的反向图,只是边权和之前的图一样,但是方向是相反的,那么是不是可以另开一个数组存图呢?当然可以,但是这样的话工作量可能会比较巨大,所以我们只需要在原有数组的基础上加一个偏移量即可,而且此时所计算的答案刚好是两次所计算的最短路径的总和。

首先一定一定要注意的就是在返回起点的时候肯定是不可以走来时候的路,那么现在只要抛开不看这条路,那么从这个点到1的最短路是不是就相当于1到这个点的另一条最短路(抛开来时的路不看),这就是反向建图的内涵所在!!!!

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值