背景
湖南師大附中成爲百年名校之後,每年要接待大批的遊客前來參觀。學校認爲大力發展旅遊業,可以帶來一筆可觀的收入。
描述
學校裏面有N個景點。兩個景點之間可能直接有道路相連,用Dist[I,J]表示它的長度;否則它們之間沒有直接的道路相連。這裏所說的道路是沒有規定方向的,也就是說,如果從I到J有直接的道路,那麼從J到I也有,並且長度與之相等。學校規定:每個遊客的旅遊線路只能是一個迴路(好霸道的規定)。也就是說,遊客可以任取一個景點出發,依次經過若干個景點,最終回到起點。一天,Xiaomengxian決定到湖南師大附中旅遊。由於他實在已經很累了,於是他決定儘量少走一些路。於是他想請你——一個優秀的程序員——幫他求出最優的路線。怎麼樣,不是很難吧?(摘自《鬱悶的出納員》)
格式
輸入格式
對於每組數據:
第一行有兩個正整數N,M,分別表示學校的景點個數和有多少對景點之間直接有邊相連。(N<=100,M<=10000)
以下M行,每行三個正整數,分別表示一條道路的兩端的編號,以及這條道路的長度。
輸出格式
對於每組數據,輸出一行:
如果該回路存在,則輸出一個正整數,表示該回路的總長度;否則輸出“No solution.”(不要輸出引號)
分析
就是找無向圖的最小環問題。如果用Dijsktra,每次刪掉圖中的一條邊(u,v),找從u到v的最短路,再加上w[u,v]即可,時間複雜度爲O(E(E+VlogV)),然而題目數據給的E可能很大…
所以用Floyd的修改版寫好了…
代碼
#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxn 100+10
#define INF 1000000//這道題好坑的,INF太大了會WA?
using namespace std;
int n,m,a,b,c,dist[maxn][maxn],edge[maxn][maxn],ans=INF;
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++) if(i==j) {
edge[i][j]=dist[i][j]=0;
} else {
edge[i][j]=dist[i][j]=INF;
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
dist[a][b]=dist[b][a]=c;
edge[a][b]=edge[b][a]=c;
}
//設環的起點(終點)爲i,那麼環可以表示爲i->k->j->x1,x2...(不經過k)->i
//環的長度可以表示爲i->j經過k的dist+i->不經過k的dist
//i->j經過k的dist普通floyd就能求到,不經過k的dist需要構造
//在求這個環時,保持k是最大值,那麼所有x1,x2...都比k要小
//循環遍歷至k-1時存儲的就是j->x1,x2...->i的最小值
for(int k=1;k<=n;k++){//k是用來更新的中間點,保持k比i,j都要大,
for(int i=1;i<k;i++)//floyd每次更新從i開始到j結束,中間經過k的距離
for(int j=i+1;j<k;j++){
ans=min(ans,dist[i][j]+edge[i][k]+edge[k][j]);
}
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
dist[i][j]=min(dist[i][j],dist[i][k]+dist[k][j]);
}
if(ans<INF) printf("%d\n",ans);
else printf("No solution.\n");
ans=INF;
}
return 0;
}