[USACO2007FEBS] Cow Party S

题目描述

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

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

输入格式

第一行有三个整数,分别表示牛的数量 \(n\),道路数 \(m\) 和派对农场编号 \(x\)
接下来 \(m\) 行,每行三个整数 \(u, v, w\),表示存在一条由 \(u\) 通向 \(v\) 的长度为 \(w\) 的道路。

输出格式

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

样例 #1

样例输入 #1

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

样例输出 #1

10

提示

样例 1 解释

数据规模与约定

对于全部的测试点,保证 \(1 \leq x \leq n \leq 10^3\)\(1 \leq m \leq 10^5\)\(1 \leq u,v \leq n\)\(1 \leq w \leq 10^2\),保证从任何一个结点出发都能到达 \(x\) 号结点,且从 \(x\) 出发可以到达其他所有节点。

考虑最短路,先从起始点跑一边dijkstra,然后把所有的边反过来,再跑一边dijkstra,我们就可以知道每个点一来一回的距离。找个最大的就可以了。
不要用SPFA,n*m会爆。

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
const int N=1e6+5;
int n,m;
int head[N];
int u[N],v[N],x;
long long w[N],dis[N],ret[N];
struct edge{
	int v,nxt;
	long long w;
}e[N];
int idx;
void add_edge(int u,int v,int w)
{
	e[++idx].v=v;
	e[idx].w=w;
	e[idx].nxt=head[u];
	head[u]=idx;
}
struct node{
	int v;
	long long dis;
	bool operator<(const node&n)const{
		return dis>n.dis;
	}
};
priority_queue<node>pq;
bool vis[N];
void dijskra(int s)
{
	dis[s]=0;
	pq.push((node){s,0});
	while(!pq.empty())
	{
		int k=pq.top().v;
		pq.pop();
		if(vis[k])
			continue;
		vis[k]=1;
		for(int i=head[k];i;i=e[i].nxt)
		{
			if(!vis[e[i].v]&&dis[e[i].v]>dis[k]+e[i].w)
			{
				dis[e[i].v]=dis[k]+e[i].w;
				pq.push((node){e[i].v,dis[e[i].v]});
			}
		}
	}
}
long long ans;
int main()
{
	cin>>n>>m>>x;
	for(int i=1;i<=m;i++)
	{
		cin>>u[i]>>v[i]>>w[i];
		add_edge(u[i],v[i],w[i]);
	}
	memset(dis,1,sizeof(dis));
	dijskra(x);
	memcpy(ret,dis,sizeof(dis));
	memset(dis,1,sizeof(dis));
	memset(head,0,sizeof(head));
	memset(vis,0,sizeof(vis));
	idx=0;
	for(int i=1;i<=m;i++)
		add_edge(v[i],u[i],w[i]);
	dijskra(x);
	for(int i=1;i<=n;i++)
		ans=max(ans,ret[i]+dis[i]);
	cout<<ans<<endl;
}
posted @ 2022-06-06 13:35  灰鲭鲨  阅读(36)  评论(0编辑  收藏  举报