【Luogu P1821】Cow Party S

C o w   P a r t y   S Cow\ Party\ S Cow Party S


L u o g u   P 1821 Luogu\ P1821 Luogu P1821


题目描述

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

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

中最长的一条路径长度。

输入格式

第一行有三个整数,分别表示牛的数量 n,道路数 m 和派对农场编号 x。

接下来 m 行,每行三个整数 u,v,w,表示存在一条由 u 通向 v 的长度为 w 的道路。

输出格式

输出一行一个整数表示答案。


输入输出样例

输入

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

说明/提示

样例 1 解释

在这里插入图片描述

数据规模与约定

对于全部的测试点,保证 1≤x≤n≤10 ^3,1≤m≤10 ^5 ,1≤u,v≤n,1≤w≤10 ^2 ,保证从任何一个结点出发都能到达 x 号结点,且从

x 出发可以到达其他所有节点。


解题思路

这题求的是最短路,用两边SPFA来求即可.

详见在相似题

程序如下

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,p,u,v,w,ans,t[1000001],tt[1000001],k,d[1000001],dd[1000001],x;
struct node
{
	int to,next,x;//to表示这个儿子是谁   next表示下一个儿子的位置  x表示父亲到当前儿子的边的距离(值) 
}e1[2000001],e2[2000001];
queue<int>q;
bool in[1000001];
int main()
{
	memset(d, 0x7f, sizeof(d));
	memset(dd, 0x7f, sizeof(dd));
	scanf("%d%d%d",&n,&m,&x);
	p = x;
	for(int i = 1;i <= m;++i)
	{
		scanf("%d%d%d",&u,&v,&w);
		e1[++k] = (node){v, t[u], w}; 
		t[u] = k;
		e2[k] = (node){u, tt[v], w}; 
		tt[v] = k;
	}
	q.push(p);//起点插入队列 
	in[p] = 1;//记录到过这个点 
	d[p] = 0;//距离 
	while(!q.empty())//还有下一个点可以走 
	{
		int now = q.front();//现在在那个点 
			q.pop();//把这个点弹出去 
		for (int  i = t[now]; i; i = e1[i].next)//枚举它所有到的点 
		{
			int y = e1[i].to;//到它的下一个点 
			if (d[now] + e1[i].x < d[y])//这里不需要改动
			{
				d[y] = d[now] + e1[i].x;//如果更短,就更新值 
				if (!in[y])//如果没有到过这个点(避免死循环) 
				{
					in[y] = 1;//标记它走过 
					q.push(y);//插入点继续走 
				}
			}
		}
		in[now] = 0;//把不在路径上的点的标记清除 
	}
	
	q.push(p);
	in[p] = 1;
	dd[p] = 0;
	while(!q.empty()) 
	{
		long long now = q.front();
		q.pop();
		for (long long i = tt[now]; i; i = e2[i].next) 
		{
			long long y = e2[i].to;
			if (dd[now] + e2[i].x < dd[y]) 
			{
				dd[y] = dd[now] + e2[i].x;
				if (!in[y]) 
				{
					in[y] = 1;
					q.push(y);
				}
			}
		}
		in[now] = 0;
	}
	
	for(int i = 1;i <= n; ++i)
	{
		if (i != x) 
		{
			ans = max(ans, d[i] + dd[i]);
		}
	}
	printf("%d",ans);
	return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值