P1821[USACO07FEB] 题解

题目意思

题目链接
寒假到了, n n n 头牛都要去参加一场在编号为 x x x 的牛的农场举行的派对,农场之间有 m m m 条有向路,每条路都有一定的长度。

每头牛参加完派对后都必须回家,无论是去参加派对还是回家,每头牛都会选择最短路径,求这 n n n 头牛的最短路径(一个来回)中最长的一条路径长度。

样例输入

4 8 2
1 2 4
1 3 2
1 4 7
2 1 1
2 3 5
3 1 2
3 4 4
4 2 3

样例输出

10

解释

在这里插入图片描述

思路

可以发现,从 x x x 点返回 n n n 个点的方式可以用单源最短路的方式解决。为了解决从多个点来到 x x x 号点的情况,可以考虑建一个反向图,再跑一遍单源最短路,从而统计出两次所耗费的时间和。

代码

#include<bits/stdc++.h>
using namespace std;
struct edge{
	int to,w;
	bool operator <( const edge &x )const {
        return x.w < w;
    }
}e[500005];
int head[500005],en,nex[500005];
bool v[500005];
void add(int x,int y,int ww){
	nex[++en] = head[x];
	head[x] = en;
	e[en].to = y;
	e[en].w = ww;
	return;   
}
int kk[500005],kk1[500005];
struct edge1{
	int to,w;
	bool operator <( const edge1 &x )const {
        return x.w < w;
    }
}e1[500005];
int head1[500005],en1,nex1[500005];
bool v1[500005];
void add1(int x,int y,int ww){
	nex1[++en1] = head1[x];
	head1[x] = en1;
	e1[en1].to = y;
	e1[en1].w = ww;
	return;   
}
int main() {
	int n,m,s;
	scanf("%d%d%d",&n,&m,&s);
	for(int i = 1;i <= m;i++) {
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		add(u,v,w);	
		add1(v,u,w);	
	}
	for(int i = 1;i <= n;i++) {
		kk[i] = pow(2,31) - 1;
		kk1[i] = pow(2,31) - 1;
	}
	kk[s] = 0;
	priority_queue<edge>q;
	q.push((edge){s,0});
	while(!q.empty()) {
		edge ssoi = q.top();
		q.pop();
        int minv = ssoi.to;
		v[minv] = true;
		for(int j = head[minv];j;j = nex[j]){
			if(!v[e[j].to]) {
				if(kk[e[j].to] > kk[minv] + e[j].w) {
					kk[e[j].to] = kk[minv] + e[j].w;
					q.push((edge){e[j].to,kk[e[j].to]});
				}
			}
		}
	}
	//
	kk1[s] = 0;
	priority_queue<edge1>q1;
	q1.push((edge1){s,0});
	while(!q1.empty()) {
		edge1 ssoi = q1.top();
		q1.pop();
        int minv = ssoi.to;
		v1[minv] = true;
		//printf("%lld:",minv); 
		for(int j = head1[minv];j;j = nex1[j]){
			//printf("%lld %lld %lld %lld\n",e1[j].to,kk1[e1[j].to],kk1[minv],e1[j].w);
			if(!v1[e1[j].to]) {
				if(kk1[e1[j].to] > kk1[minv] + e1[j].w) {
					kk1[e1[j].to] = kk1[minv] + e1[j].w;
					q1.push((edge1){e1[j].to,kk1[e1[j].to]});
				}
			}
		}
	}
	for(int i = 1;i <= n;i++) kk[i] += kk1[i];
	sort(kk + 1,kk + n + 1);
	printf("%lld\n",kk[n]);
}

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值