题意:
给出一个有向图,n 个农庄,每个农庄有 1 头牛,m 条道路,每条道路花费 T 时间。有 n-1 头牛要去给 x 号农庄的牛过party,且要返回,每头牛要走最小时间的路,问所有牛中花费最大时间的那头牛的时间。
数据范围:
1 ≤ N ≤ 1000 1 ≤ N ≤ 1000 1≤N≤1000, 1 ≤ M ≤ 100 , 000 1 ≤ M ≤ 100,000 1≤M≤100,000
思路:
因为是有向图,起先想着:去时给每头牛来个 dijkstra,回来时给
x
x
x 来个dijkstra,可是用二维数组存图,最短路的时间复杂度就要
O
(
n
2
)
O(n^2)
O(n2) 再遍历每头牛,就要
O
(
n
3
)
O(n^3)
O(n3) ,不行,复杂度太大了。再深入思考,朴素的Dijkstra 是单源多终点,仅仅能解决回来时的情况,而去时的情况是多源单终点,问题是要求
1
−
>
2
,
3
−
>
2
,
4
−
>
2
1->2,3->2,4->2
1−>2,3−>2,4−>2的最短距离,这就等价于,如果一开始的时候给我的图是
2
−
>
1
,
2
−
>
3
,
2
−
>
4
2->1,2->3,2->4
2−>1,2−>3,2−>4就好了,所以想到了用转置矩阵,mp[i][j]=mp[j][i]
输入:
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
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N =1010;
const int inf = 0x3f3f3f3f;
int n,m,x;
int mp[N][N];
int dist[N],ans[N];
bool vis[N];
int findMin()
{
int k,mn=inf;
for(int i=1;i<=n;i++)
{
if(!vis[i]&&dist[i]<mn)
{
mn=dist[i];
k=i;
}
}
return k;
}
void dij(int u) //板子
{
memset(dist,inf,sizeof dist);
memset(vis,false,sizeof vis);
for(int i=1;i<=n;i++)
dist[i]=mp[u][i];
dist[u]=0;
vis[u]=true;
for(int i=1;i<n;i++)
{
int tmp=findMin();
vis[tmp]=true;
for(int j=1;j<=n;j++)
if(!vis[j] && dist[j]>dist[tmp]+mp[tmp][j])
dist[j]=dist[tmp]+mp[tmp][j];
}
}
void Trans()//转置矩阵
{
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
swap(mp[i][j],mp[j][i]);
}
int main()
{
cin>>n>>m>>x;
int u,v,t;
memset(mp,inf,sizeof mp); //初始化图
memset(ans,0,sizeof ans);
while(m--)
{
scanf("%d %d %d",&u,&v,&t);
mp[u][v]=t;
}
dij(x); //从农场 x 回来时的最小距离
for(int i=1;i<=n;i++)
ans[i]=dist[i];
Trans();
dij(x); //转置后 就是每头牛去时的最小距离
int mx=-inf;
for(int i=1;i<=n;i++) //找出花费的最大时间 mx
{
ans[i]+=dist[i];
if(mx<ans[i])
mx=ans[i];
}
printf("%d\n",mx);
return 0;
}