題意:
給你一張無向圖,求從S到E恰好經過N條邊(可重複走)的最短路。
分析:
(1):根據Floyd演算法的特殊性,它是通過插入點的方法來找到最短路的,特別適合此題,假如我們插入N-1個點,求到的則是經過N條邊的最短路。假設我們每一次floyd只插入一個點的話,那麼單步Floyd N次的話,則可以插入N個點。
(2):而N次floyd可以用倍增思想加速,就是自底向上的二分。類似求矩陣A^N。
(3):這裡還有一點要注意,T的範圍是(2~100),所以最多頂點只有200,而頂點標號的範圍卻(1 ≤ I1i ≤ 1,000; 1 ≤ I2i ≤ 1,000)。這樣我們可以將編號離散化,開map時只需開到map[205][205],既節省了記憶體,又使所以結點的編號連續,加快了速度。
(4):還有一點比較鬱悶,一開始INF是定義成99999999,不停的WA,改成100000001就AC了。。。囧。。。。。看來以後一定要往大開。。。。不然怎麼死都不知道。。。唉
原始碼:
/*Floyd(倍增法)*//*N次Floyd*//*求從S到E恰好經過N條邊(可重複走)的最短路。*//*AC代碼:125ms*/#include <iostream>#define MAXN 210#define INF 1000000000//注意,原來寫99999999會WA!!!int v[1005];//存那些牛的頂點(離散化)int map[MAXN][MAXN];//存原地圖int ans[MAXN][MAXN];//存答案int temp[MAXN][MAXN];//臨時儲存int cnt;int N,T,S,E;void Init(){int val,s,e,i,j;for(i=0;i<205;i++)//因為離散化後最多隻有200個點{for(j=0;j<205;j++)map[i][j]=ans[i][j]=temp[i][j]=INF;ans[i][i]=0;}cnt=0;memset(v,0,sizeof(v));for(i=1;i<=T;i++){scanf("%d%d%d",&val,&s,&e);if(v[s]==0)//連續化結點編號,提高運行效率{cnt++;v[s]=cnt;}if(v[e]==0){cnt++;v[e]=cnt;}if(map[v[s]][v[e]]>val)map[v[s]][v[e]]=map[v[e]][v[s]]=val;}}void floyd(int a[MAXN][MAXN],int b[MAXN][MAXN],int c[MAXN][MAXN]){int i,j,k;for(k=1;k<=cnt;k++)for(i=1;i<=cnt;i++)for(j=1;j<=cnt;j++)if(a[i][j]>b[i][k]+c[k][j])a[i][j]=b[i][k]+c[k][j];}void copy(int a[MAXN][MAXN],int b[MAXN][MAXN]){int i,j;for(i=1;i<=cnt;i++)for(j=1;j<=cnt;j++){a[i][j]=b[i][j];b[i][j]=INF;}}void work(int n)//N次Floyd{while(n){if(n&1){floyd(temp,ans,map);//多出來的1先加到anscopy(ans,temp);}floyd(temp,map,map);copy(map,temp);n>>=1;} }int main(){while(scanf("%d%d%d%d",&N,&T,&S,&E)!=EOF){Init();work(N);printf("%d\n",ans[v[S]][v[E]]);}return 0;}