1. 程式人生 > 其它 >Cow Party S

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