題目鏈接
題目大意
給定一個有N(1
分析
對於每個結點,要在它與X號結點之間走一個來回花費最小,必定它到X要走最短路,從X回到它也要走最短路。
返回的最短路好解決,即X號結點出發到其他結點的單源最短路,用Dijkstra算法跑一遍即可。現在關鍵要解決從其他結點到X號結點的最短路,這種情況下起點是多個,而終點是一個,與單源最短路徑的情況恰好相反,如果再每個點作爲起點用Dijkstra複雜度就較高了。處理方法是:反向建圖,再求X到其他結點的單源最短路。(道路反向,起點與終點互換,問題等效)
最後答案爲Max(dis[i],dis2[i]).
代碼
#include <iostream>
#include <cstdio>
#include <cstring>
#define Max(a,b) (a>b?a:b)
using namespace std;
const int INF=99999999;
const int MAXN=1010;
const int MAXM=100010;
int e[MAXN][MAXN],e2[MAXN][MAXN],dis[MAXN],dis2[MAXN],book[MAXN],book2[MAXN];
int n,m,x;
void Init()//鄰接矩陣初始化
{
int i,j;
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
e[i][j]=(i==j?0:INF);
for (i=1;i<=n;i++)
for (j=1;j<=n;j++)
e2[i][j]=(i==j?0:INF);
}
void Dijkstra()
{
int i,j,u,v,mind;
for (i=1;i<=n;i++)
dis[i]=e[x][i];
memset(book,0,sizeof(book));
book[x]=1;
for (i=1;i<=n-1;i++)
{
mind=INF;
for (j=1;j<=n;j++)
if (dis[j]<mind&&!book[j])
{
mind=dis[j];
u=j;
}
book[u]=1;
for (v=1;v<=n;v++)
if ((e[u][v]<INF)&&(dis[v]>dis[u]+e[u][v]))
dis[v]=dis[u]+e[u][v];
}
}
void Dijkstra2()//對反向圖的計算
{
int i,j,u,v,mind;
for (i=1;i<=n;i++)
dis2[i]=e2[x][i];
memset(book2,0,sizeof(book2));
book2[x]=1;
for (i=1;i<=n-1;i++)
{
mind=INF;
for (j=1;j<=n;j++)
if (dis2[j]<mind&&!book2[j])
{
mind=dis2[j];
u=j;
}
book2[u]=1;
for (v=1;v<=n;v++)
if ((e2[u][v]<INF)&&(dis2[v]>dis2[u]+e2[u][v]))
dis2[v]=dis2[u]+e2[u][v];
}
}
int main()
{
int a,b,c,i,ans;
scanf("%d%d%d",&n,&m,&x);
Init();
while (m--)
{
scanf("%d%d%d",&a,&b,&c);
e[a][b]=c;
e2[b][a]=c;//反向建圖
}
Dijkstra();
Dijkstra2();
ans=-1;
for (i=1;i<=n;i++)
ans=Max(ans,dis[i]+dis2[i]);
printf("%d\n",ans);
return 0;
}