vijos 觀光旅遊 最小環fl 呆詳看
背景
湖南師大附中成為百年名校之後,每年要接待大批的遊客前來參觀。學校認為大力發展旅遊業,可以帶來一筆可觀的收入。
描述
學校裏面有N個景點。兩個景點之間可能直接有道路相連,用Dist[I,J]表示它的長度;否則它們之間沒有直接的道路相連。這裏所說的道路是沒有規定方向的,也就是說,如果從I到J有直接的道路,那麽從J到I也有,並且長度與之相等。學校規定:每個遊客的旅遊線路只能是一個回路(好霸道的規定)。也就是說,遊客可以任取一個景點出發,依次經過若幹個景點,最終回到起點。一天,Xiaomengxian決定到湖南師大附中旅遊。由於他實在已經很累了,於是他決定盡量少走一些路。於是他想請你——一個優秀的程序員——幫他求出最優的路線。怎麽樣,不是很難吧?(摘自《郁悶的出納員》)
格式
輸入格式
對於每組數據:
第一行有兩個正整數N,M,分別表示學校的景點個數和有多少對景點之間直接有邊相連。(N<=100,M<=10000)
以下M行,每行三個正整數,分別表示一條道路的兩端的編號,以及這條道路的長度。
輸出格式
對於每組數據,輸出一行:
如果該回路存在,則輸出一個正整數,表示該回路的總長度;否則輸出“No solution.”(不要輸出引號)
樣例1
樣例輸入1
5 7
1 4 1
1 3 300
3 1 10
1 2 16
2 3 100
2 5 15
5 3 20
4 3
1 2 10
1 3 20
1 4 30
樣例輸出1
61
No solution.
限制
各個測試點1s
by http://wenku.baidu.com/view/c6382a41a8956bec0975e3c0.html?from=related
http://blog.csdn.net/youngyangyang04/article/details/7054931
典型的最小環問題
因為n很小可以直接Floyd求最小環
註意最小環ans更新的位置
每次枚舉k為下家更新點
應該先嘗試更新ans再更新i,j之間的最短路
我們用g[i][j]來記錄i,j之間最短路徑
而w[i][j]用來保存i,j之間的原始路徑長度
因為我們知道i,j要構成一個最小環
肯定要有兩條路可走
1.直接從i到j。
2.從i經過某個中途點k到達j
即對於每一個k 我們先嘗試從這個k點對於所有的i,j點能不能得到最小環
然後我們再用這個k點嘗試更新路徑
該算法的證明:
一個環中的最大結點為K(編號最大),與其相連的兩個點為i,j ,
這個環的最短長度為: g[i][k] + g[k][j] + i到j的路徑中所有結點編號都不大於k的最短路徑長度,
根據floyd的原理,在最外層循環做一個k-1次之後,
g[i][j] 則代表了i到j的路徑中所有結點的編號都不大於k的最短路徑。
所以我們枚舉的i,j要有
1<=i<k,i<j<k
再換一種說法吧
比普通Floyd多出來的部分,主要利用到的原理是當處理到k時,
所有以1 到k - 1為中間結點的最短路徑都已經確定,
則這時候的環為(i到j(1 < i, j <= k - 1)的最短路徑) + 邊(i, k) + 邊(k, j)
遍歷所有的i, j找到上述式子的最小值即位k下的最小代價環
*/
/*
路徑的求法:
用一個pre[i][j]記錄j前面的一個頂點, 初始化為i,當出現需要更新的時候則將pre[i][j] = pre[k][j];
若i== j的時候則表示找全了路徑,最後將k點加入路徑中
核心代碼:
While(i != j)
{
if (i != j)
{
Path[len++] = j;
J = pre[i][j];
}
Path[len++] = i;
}
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> using namespace std; const int INF=1e8; int w[102][102],g[102][102]; int n,e; void init() { int x,y,v; for(int i=1;i<=n;i++) for(int j=1;j<=n;j++) w[i][j]=g[i][j]=INF; for(int i=1;i<=e;i++) { scanf("%d%d%d",&x,&y,&v); w[x][y]=w[y][x]=g[x][y]=g[y][x]=v; } } void work() { int ans=INF; for(int k=1;k<=n;k++) { for(int i=1;i<k;i++)//最小環 for(int j=i+1;j<k;j++)//為了避免一條邊計算兩次並且i == j時因為權重會出錯 ans=min(ans,g[i][j]+w[i][k]+w[k][j]); for(int i=1;i<=n;i++)//Floyd for(int j=1;j<=n;j++) if(i!=j) g[i][j]=min(g[i][j],g[i][k]+g[k][j]); } if(ans==INF) printf("No solution.\n"); else printf("%d\n",ans); } int main() { while(scanf("%d%d",&n,&e)!=EOF) { init(); work(); } }
vijos 觀光旅遊 最小環fl 呆詳看