题目链接:http://poj.org/problem?id=3268
题目大意:有编号为1-N的牛,它们之间存在一些单向的路径。给定一头牛的编号,其他牛要去拜访它并且拜访完之后要返回自己原来的位置,求这些牛中所花的最长的来回时间是多少。
每头牛返回的最短时间从目标牛为起点求单源最短路径。但每头牛出发到目标牛的最短时间无法直接算出来,稍微转换一下,发现这个最短时间其实可以通过把所有的边取反向(矩阵转置) 。然后再从目标牛求一次单源最短路径得到。得到这两个最短路径之后,取它们的和的最大者即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <functional>
#include <map>
#include <string>
#include <vector>
#include <stack>
#include <queue>
#include <cmath>
#include <set>
using namespace std;
const int maxn=1005;
vector< pair<int ,int > > e[maxn];
int n, m, x;
int d1[maxn], vis[maxn]; //dis当前的最短路 vis是否在队列中
int d2[maxn];
struct E
{
int x, y, z;
}node[100005];
queue<int> q;
void spfa(int s, int t, int dis[])
{
while(!q.empty())
{
q.pop();
}
q.push(s);
dis[s]=0, vis[s]=1;
while(!q.empty())
{
int now=q.front();
q.pop(), vis[now]=0;
for(int i=0;i<e[now].size();i++)//访问所有的邻接点
{
int v=e[now][i].first;
if(dis[v]>dis[now]+e[now][i].second)
{
dis[v]=dis[now]+e[now][i].second;
if(vis[v]==1)
{
continue;
}
q.push(v); //把所有不在队列的邻接点加入队列
vis[v]=1;
}
}
}
}
int main()
{
while(scanf("%d%d%d",&n,&m,&x)!=EOF)
{
for(int i=0;i<maxn;i++) //初始化
{
d1[i]=1e9;
d2[i]=1e9;
vis[i]=0;
e[i].clear();
}
for(int i=0;i<m;i++)
{
int x, y, z;
scanf("%d%d%d",&x,&y,&z);
node[i].x=x, node[i].y=y, node[i].z=z;
e[x].push_back(make_pair(y ,z));
}
spfa(x, n, d1);
for(int i=0;i<maxn;i++)//取反再跑spfa
{
vis[i]=0;
e[i].clear();
}
for(int i=0;i<m;i++)
{
int x=node[i].x, y=node[i].y, z=node[i].z;
e[y].push_back(make_pair(x ,z));
}
spfa(x, n, d2);
int ans=0;
for(int i=1;i<=n;i++)
{
ans=max(ans, d1[i]+d2[i]);
}
printf("%d\n",ans);
}
return 0;
}