P1629 邮递员送信(最短路)(内附封面)

邮递员送信

题目描述

有一个邮递员要送东西,邮局在节点 1 1 1。他总共要送 n − 1 n-1 n1 样东西,其目的地分别是节点 2 2 2 到节点 n n n。由于这个城市的交通比较繁忙,因此所有的道路都是单行的,共有 m m m 条道路。这个邮递员每次只能带一样东西,并且运送每件物品过后必须返回邮局。求送完这 n − 1 n-1 n1 样东西并且最终回到邮局最少需要的时间。

输入格式

第一行包括两个整数, n n n m m m,表示城市的节点数量和道路数量。

第二行到第 ( m + 1 ) (m+1) (m+1) 行,每行三个整数, u , v , w u,v,w u,v,w,表示从 u u u v v v 有一条通过时间为 w w w 的道路。

输出格式

输出仅一行,包含一个整数,为最少需要的时间。

样例 #1

样例输入 #1

5 10
2 3 5
1 5 5
3 5 6
1 2 8
1 3 8
5 3 4
4 1 8
4 5 3
3 5 6
5 4 2

样例输出 #1

83

提示

对于 30 % 30\% 30% 的数据, 1 ≤ n ≤ 200 1 \leq n \leq 200 1n200

对于 100 % 100\% 100% 的数据, 1 ≤ n ≤ 1 0 3 1 \leq n \leq 10^3 1n103 1 ≤ m ≤ 1 0 5 1 \leq m \leq 10^5 1m105 1 ≤ u , v ≤ n 1\leq u,v \leq n 1u,vn 1 ≤ w ≤ 1 0 4 1 \leq w \leq 10^4 1w104,输入保证任意两点都能互相到达。

F l o y d Floyd Floyd 逃课做法(要开O2)

直接套 F l o y d Floyd Floyd

最后的结果是每个点到 1 节点的距离与 1 到每个点的距离之和,注意存储初始距离时保留最短的一条,否则会WA

F l o y d Floyd Floyd做法代码

#include<bits/stdc++.h>
using namespace std;
const int N=1e3+111;
int n,m,ans=0;
int dis[N][N];
int main(){
	cin>>n>>m;
	memset(dis,0x3f,sizeof(dis));
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		dis[u][v]=min(dis[u][v],w);
		//dis[u][v]=w;
	}
	for(int k=1;k<=n;k++){
		for(int i=1;i<=n;i++){
			for(int j=1;j<=n;j++){
				dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
			}
		}
	}
	for(int i=2;i<=n;i++){
		ans+=dis[i][1]+dis[1][i];
	}
	cout<<ans<<endl;
	return 0;
}

d i j k s t r a dijkstra dijkstra堆优化

1 1 1 跑到其他 2   n 2~n 2 n 节点需要跑一遍 d i j k s t r a dijkstra dijkstra

返回 1 1 1节点也需要跑一遍 d i j k s t r a dijkstra dijkstra

因此我们在 u + n u+n u+n v + n v+n v+n 建一个反图,方便反跑

需要堆优化

答案累加 2 2 2累加到 n n n,反跑后从 2 + n 2+n 2+n 累加到 n ∗ 2 n*2 n2即可

AC CODE

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+49999;
int n,m,ans=0;
int dis[N];
vector<pair<int,int> > a[N];
bool vis[N];
void dijkstra(int s){
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
	memset(dis,0x3f,sizeof(dis));
	memset(vis,0,sizeof(vis));
	dis[s]=0;
	q.push({0,s});
	while(!q.empty()){
		pair<int,int> tmp=q.top();
		q.pop();
		int x=tmp.second;
		int y=tmp.first;
		if(dis[x]<tmp.first)continue;
		if(vis[x]==1)continue;
		vis[x]=1;
		for(int i=0;i<a[x].size();i++){
			if(dis[a[x][i].first]>y+a[x][i].second){
				dis[a[x][i].first]=y+a[x][i].second;
				q.push({dis[a[x][i].first],a[x][i].first});
			}
		}
	}
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int u,v,w;
		cin>>u>>v>>w;
		a[u].emplace_back(make_pair(v,w));
		a[v+n].emplace_back(make_pair(u+n,w));
	}
	dijkstra(1);
	for(int i=2;i<=n;i++){
		ans+=dis[i];
	}
	dijkstra(1+n);
	for(int i=2+n;i<=n*2;i++){
		ans+=dis[i];
	}
	cout<<ans<<endl;
	return 0;
}

附封面(碧蓝档案)

请添加图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值