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;
}