P1629 邮递员送信

题目

- 题目描述

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

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

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

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

- 思路

  1. 从邮局到各个点,以1为原点的单源最短路径
  2. 从各个点到1的最短路径 ,反向建图即可
  • 代码(AC code
    链式前向星+优先队列+dijkstra
#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue> 
using namespace std;
const int maxn=1e3*2+10;
const int maxm=1e5*2+10;
int head[maxm];
int n,m;
int dis[maxn];
bool vl[maxn];
long long ans=0;
int cnt=0;
struct node{int next,v,w;}e[maxm];
void ad(int u,int v,int w){e[++cnt].v=v;e[cnt].w=w;e[cnt].next=head[u];head[u]=cnt;}
void dj(int x){
	//初始化
	memset(dis,0x7f,sizeof(dis));
	memset(vl,0,sizeof(vl));
	priority_queue<pair<int,int>,vector<pair<int,int> >,greater<pair<int,int> > >q;
	dis[x]=0;
	q.push(make_pair(dis[x],x));
	while(!q.empty()){
		pair<int ,int > t=q.top();q.pop();
		if(vl[t.second]) continue;
		vl[t.second]=1;
		for(int i=head[t.second];i;i=e[i].next){
			int v=e[i].v;
			int w=e[i].w;
			if(dis[v]>dis[t.second]+w) {
				dis[v]=dis[t.second]+w;
				q.push(make_pair(dis[v],v));
			}
		}
	}	
}
int main(){
	memset(head,0,sizeof(head));
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;++i){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		ad(u,v,w);
		ad(v+n,u+n,w);//反向建图 
	}
	dj(1); 
	for(int i=2;i<=n;++i) ans+=dis[i];
	dj(1+n); //反向建图后求到一最短路径
	for(int i=2+n;i<=n<<1;++i) ans+=dis[i];
	cout<<ans<<endl;
	return 0;
}

有疑问评论区留言或私信,欢迎互相交流讨论

posted @ 2021-04-05 13:10  归游  阅读(37)  评论(0编辑  收藏  举报