POJ 最短路問題集錦:
Dijkstra算法:
詳細介紹: http://hi.baidu.com/iotbill/item/cb5fc1de28a3e63721e250d9
Dijkstra算法是典型最短路算法,用於計算一個節點到其他所有節點的最短路徑。主要特點是以起始點為中心向外層層擴展,直到擴展到終點為止。Dijkstra算法能得出最短路徑的最優解,但由於它遍歷計算的節點很多,所以效率低。
POJ 2387 Til the Cows Come Home (problem link adress:http://poj.org/problem?id=2387)
雖然題目不是很好讀,但本題是Dijkstra算法的模板式樣題!相當於Dijkstra的模板了!
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define Max 0xfffffff 6 #define N 1005 7 int p[N][N],mark[N],f[N]; 8 int t,n; 9 void Dijkstra() 10 { 11 int i,j,k,min; 12 memset(mark,0,sizeof(mark)); 13 for(i=1;i<=n;i++) 14 f[i]=p[1][i]; 15 f[1]=0; 16 for(i=1;i<=n;i++) 17 { 18 min=Max; 19 for(j=1;j<=n;j++) 20 { 21 if(!mark[j]&&f[j]<min) 22 { 23 min=f[j]; 24 k=j; 25 } 26 } 27 if(min==Max) break; 28 mark[k]=1; 29 for(j=1;j<=n;j++) 30 { 31 if(!mark[j]&&f[j]>f[k]+p[k][j]) 32 f[j]=f[k]+p[k][j]; 33 } 34 } 35 printf("%d\n",f[n]); 36 } 37 int main() 38 { 39 int i,j; 40 while(scanf("%d%d",&t,&n)!=EOF) 41 { 42 for(i=1;i<=n;i++) 43 for(j=1;j<=n;j++) 44 p[i][j]=Max; 45 for(j=0;j<t;j++) 46 { 47 int a,b,len; 48 scanf("%d%d%d",&a,&b,&len); 49 if(p[a][b]>len) 50 p[a][b]=p[b][a]=len; 51 } 52 Dijkstra(); 53 } 54 return 0; 55 }
本題中,dijkstra中f【i】保存的是原點到節點i的最短距離。
POJ 2253 Frogger (problem link adress:http://poj.org/problem?id=2253)
第一次讀本題的時候,也感覺似懂非懂,由於刷題的順序是按照別人已經總結好的刷的,所以已經知道別人用Dijkstra解這道題,接着就把題意強扭到了第一塊石頭到第二塊石頭的最短距離,結果第二組數據沒有通過於是返回認真讀題.
前面的那么多東西需要搞懂什么是蛙跳的范圍,(最少等於出現的最長蛙跳長度在一個序列中),下面兩句話就很重要了。
The frog distance (humans also call it minimax distance) between two stones therefore is defined as the minimum necessary jump range over all possible paths between the two stones.
You are given the coordinates of Freddy's stone, Fiona's stone and all other stones in the lake. Your job is to compute the frog distance between Freddy's and Fiona's stone.
真正的把這兩句搞懂,題意就懂了。即讓我們求最小的蛙跳范圍在所有的可能路徑中;
可以從節點1開始遍歷,到下一節點(保持兩節點間距離最小),直到節點2,在這個過程中記錄蛙跳范圍。
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 using namespace std; 6 #define N 205 7 #define max 10000000.0 8 double p[N][N],f[N]; 9 int mark[N]; 10 int n; 11 int flag; 12 double getlen(double xx1,double yy1,double xx2,double yy2) 13 { 14 return sqrt(1.0*(xx1-xx2)*(xx1-xx2)+1.0*(yy1-yy2)*(yy1-yy2)); 15 } 16 double Dijkstra() 17 { 18 int i,j,k; 19 double min; 20 double temp=0; 21 memset(mark,0,sizeof(mark)); 22 for(i=1;i<=n;i++) 23 f[i]=p[1][i]; 24 f[1]=0;//把1設置為原點 25 for(i=1;i<=n;i++) 26 { 27 min=max; 28 for(j=1;j<=n;j++) 29 { 30 if(!mark[j]&&f[j]<min) 31 { 32 min=f[j]; 33 k=j; 34 } 35 } 36 if(min>temp)//temp記錄並保存蛙跳范圍 37 temp=min; 38 if(k==2)//如果按每步的最小距離遍歷到了節點2,返回蛙跳范圍 39 return temp; 40 mark[k]=1; 41 for(j=1;j<=n;j++) 42 { 43 if(!mark[j]) 44 { 45 double data=p[k][j]; 46 if(data<f[j]) 47 f[j]=data; 48 } 49 } 50 51 } 52 53 } 54 int main() 55 { 56 int i,j; flag=1; 57 while(scanf("%d",&n)&&n) 58 { 59 double x[N], y[N]; 60 memset(x,0,sizeof(x)); 61 memset(y,0,sizeof(y)); 62 for(i=1;i<=n;i++) 63 for(j=1;j<=n;j++) 64 p[i][j]=max; 65 for(i=1;i<=n;i++) 66 scanf("%lf%lf",&x[i],&y[i]); 67 for(i=1;i<=n;i++) 68 { 69 for(j=1;j<=n;j++) 70 { 71 if(i==j) continue; 72 double dis=getlen(x[i],y[i],x[j],y[j]); 73 if(p[i][j]>dis) 74 p[i][j]=p[j][i]=dis; 75 } 76 } 77 78 double w=Dijkstra(); 79 printf("Scenario #%d\n",flag++); 80 printf("Frog Distance = %.3lf\n\n",w); 81 } 82 return 0; 83 }
本題中,dijkstra中的f[i]記錄的是節點i到與它連接的節點的最短距離。
POJ 1797 Heavy Transport http://poj.org/problem?id=1797
題目大意:有n個路口,每個路口從1到n標記,每兩個路口之間有一個限重,問從1到n,最多可以載多重的物體。
本題和上一題的解法類似。注;本題求最大載重,p[i][j]初始化的時候用0或負數初始化,最后每個樣例后面要輸出一個空格;
實現過程:從節點1開始遍歷,尋找與節點1相連的最大權值邊,然后把該節點標記,以該節點為中心,然后更新該節點與周圍相連節點的權值,這樣重復進行;
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define MIN -1 6 #define N 1005 7 int t; 8 int flag; 9 int n,m; 10 int p[N][N],mark[N],f[N]; 11 int Dijkstra() 12 { 13 int i,j,k,temp,min; 14 memset(mark,0,sizeof(mark)); 15 for(i=1;i<=n;i++) 16 f[i]=p[1][i]; 17 f[1]=0;mark[1]=1; 18 temp=1000005; 19 for(i=1;i<=n;i++) 20 { 21 min=-1; 22 for(j=0;j<=n;j++) 23 { 24 if(!mark[j]&&f[j]>min) 25 { 26 min=f[j]; 27 k=j; 28 } 29 30 } 31 if(temp>min) 32 temp=min; 33 if(k==n) 34 return temp; 35 mark[k]=1; 36 for(j=1;j<=n;j++) 37 { 38 if(!mark[j]) 39 { 40 int w=p[k][j]; 41 if(w>f[j]) 42 f[j]=w; 43 } 44 } 45 46 } 47 } 48 int main() 49 { 50 int i,j; 51 scanf("%d",&t); 52 flag=1; 53 while(t--) 54 { 55 scanf("%d%d",&n,&m); 56 for(i=1;i<=n;i++) 57 for(j=0;j<=n;j++) 58 p[i][j]=MIN; 59 for(i=1;i<=m;i++) 60 { 61 int a,b,len; 62 scanf("%d%d%d",&a,&b,&len); 63 if(p[a][b]<len) 64 p[a][b]=p[b][a]=len; 65 } 66 printf("Scenario #%d:\n",flag++); 67 printf("%d\n\n",Dijkstra()); 68 } 69 return 0; 70 }
本題中,dijkstra中的f【j】記錄的是節點i到與它連接的節點的最長距離。
上述三題可以知道,根據題目的不同,dijkstra可以做出相應的變化來適合題目。其中,處理最短路的問題時可以用f【i】來保存,原點來目標點的最小距離,處理最大或者最小的邊權值時可以用f【i】來保存當前節點與下一節點的最短或最長距離,兩者的實現都要通過一個循環來不斷的松弛實現。
POJ 3268 Silver Cow Party http://poj.org/problem?id=3268
題意:一群牛(每頭牛居住一個的農場,標號從1到n)到第n頭牛家里聚會,牛很聰明啊!走的都是最短路,聚會結束,牛各回各家,但是就不能沿着原路返回了,因為是單程的!
問這群牛中誰花費的時間最長?
這樣的單向圖以前很少做!菜鳥想的簡單啊!以為f【i】=p【i】【x】記錄的就是 i 牛向x牛奔去最短的距離, b【i】=p【x】【i】記錄的就是從x牛的農場各自奔回自己的家中;
於是敲了兩次Dijkstra,交上去居然錯了! Google一下原來涉及單向圖的時候,反過來的時候還是需要轉置的,學習了!
WA 代碼:
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define N 1005 6 #define max 0xfffffff 7 int n,m,x; 8 int f[N],b[N],mark[N],p[N][N]; 9 void Dijkstra_go() 10 { 11 int i,j,k,min; 12 memset(mark,0,sizeof(mark)); 13 for(i=1;i<=n;i++) 14 f[i]=p[i][x]; 15 f[x]=0; 16 mark[x]=1; 17 for(i=1;i<=n;i++) 18 { 19 min=max; 20 for(j=1;j<=n;j++) 21 { 22 if(!mark[j]&&f[j]<min) 23 { 24 min=f[j]; 25 k=j; 26 } 27 } 28 if(min==max) break; 29 mark[k]=1; 30 for(j=1;j<=n;j++) 31 { 32 if(!mark[j]&&f[j]>f[k]+p[k][j]) 33 f[j]=f[k]+p[k][j]; 34 } 35 } 36 // for(i=1;i<=n;i++) 37 // printf("%d ",f[i]); 38 // printf("\n"); 39 } 40 void Dijkstra_back() 41 { 42 int i,j,k,min; 43 memset(mark,0,sizeof(mark)); 44 for(i=1;i<=n;i++) 45 b[i]=p[x][i]; 46 b[x]=0; 47 mark[x]=1; 48 for(i=1;i<=n;i++) 49 { 50 min=max; 51 for(j=1;j<=n;j++) 52 { 53 if(!mark[j]&&b[j]<min) 54 { 55 min=b[j]; 56 k=j; 57 58 } 59 } 60 if(min==max) break; 61 mark[k]=1; 62 for(j=1;j<=n;j++) 63 { 64 if(!mark[j]&&b[j]>b[k]+p[k][j]) 65 b[j]=b[k]+p[k][j]; 66 67 } 68 } 69 // for(i=1;i<=n;i++) 70 // printf("%d ",b[i]); 71 // printf("\n"); 72 } 73 74 75 76 int main() 77 { 78 int i,j; 79 while(scanf("%d%d%d",&n,&m,&x)!=EOF) 80 { 81 for(i=1;i<=n;i++) 82 for(j=1;j<=n;j++) 83 p[i][j]=max; 84 for(i=1;i<=m;i++) 85 { 86 int a,b,len; 87 scanf("%d%d%d",&a,&b,&len); 88 if(p[a][b]>len) 89 p[a][b]=len; 90 } 91 memset(f,0,sizeof(f)); 92 memset(b,0,sizeof(f)); 93 Dijkstra_go(); 94 Dijkstra_back(); 95 int ans=-1; 96 for(i=1;i<=n;i++) 97 { 98 f[i]+=b[i]; 99 if(f[i]>ans) 100 ans=f[i]; 101 } 102 printf("%d\n",ans); 103 } 104 return 0; 105 }
參考后修改的AC代碼:
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 #define N 1005 6 #define max 0xfffffff 7 int n,m,x; 8 int f[N],b[N],mark[N],p1[N][N],p2[N][N]; 9 void Dijkstra_go() 10 { 11 int i,j,k,min; 12 memset(mark,0,sizeof(mark)); 13 for(i=1;i<=n;i++) 14 f[i]=p1[x][i]; 15 f[x]=0; 16 mark[x]=1; 17 for(i=1;i<=n;i++) 18 { 19 min=max; 20 for(j=1;j<=n;j++) 21 { 22 if(!mark[j]&&f[j]<min) 23 { 24 min=f[j]; 25 k=j; 26 } 27 } 28 if(min==max) break; 29 mark[k]=1; 30 for(j=1;j<=n;j++) 31 { 32 if(!mark[j]&&f[j]>f[k]+p1[k][j]) 33 f[j]=f[k]+p1[k][j]; 34 } 35 } 36 // for(i=1;i<=n;i++) 37 // printf("%d ",f[i]); 38 // printf("\n"); 39 } 40 void Dijkstra_back() 41 { 42 int i,j,k,min; 43 memset(mark,0,sizeof(mark)); 44 for(i=1;i<=n;i++) 45 b[i]=p2[x][i]; 46 b[x]=0; 47 mark[x]=1; 48 for(i=1;i<=n;i++) 49 { 50 min=max; 51 for(j=1;j<=n;j++) 52 { 53 if(!mark[j]&&b[j]<min) 54 { 55 min=b[j]; 56 k=j; 57 58 } 59 } 60 if(min==max) break; 61 mark[k]=1; 62 for(j=1;j<=n;j++) 63 { 64 if(!mark[j]&&b[j]>b[k]+p2[k][j]) 65 b[j]=b[k]+p2[k][j]; 66 67 } 68 } 69 // for(i=1;i<=n;i++) 70 // printf("%d ",b[i]); 71 // printf("\n"); 72 } 73 74 75 76 int main() 77 { 78 int i,j; 79 while(scanf("%d%d%d",&n,&m,&x)!=EOF) 80 { 81 for(i=1;i<=n;i++) 82 for(j=1;j<=n;j++) 83 { 84 p1[i][j]=max; 85 p2[i][j]=max; 86 } 87 for(i=1;i<=m;i++) 88 { 89 int a,b,len; 90 scanf("%d%d%d",&a,&b,&len); 91 if(p1[a][b]>len) 92 { 93 p1[a][b]=len; 94 p2[b][a]=len; 95 } 96 } 97 memset(f,0,sizeof(f)); 98 memset(b,0,sizeof(f)); 99 Dijkstra_go(); 100 Dijkstra_back(); 101 int ans=-1; 102 for(i=1;i<=n;i++) 103 { 104 f[i]+=b[i]; 105 if(f[i]>ans) 106 ans=f[i]; 107 } 108 printf("%d\n",ans); 109 } 110 return 0; 111 }
POJ 1847 Tram http://poj.org/problem?id=1847
汗!本題居然沒讀懂!英語太菜了!呵呵。。。四級含金量不高啊!搜了篇文章才弄懂題意。
本題最大的挑戰就是讀題,題目弄清楚了,就ok了! Dijkstra的應用!
View Code
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 using namespace std; 5 #define N 105 6 #define max 0xfffffff 7 int f[N],mark[N],p[N][N]; 8 int n,a,b; 9 void Dijkstra() 10 { 11 int i,j,k,min; 12 memset(mark,0,sizeof(mark)); 13 for(i=1;i<=n;i++) 14 f[i]=p[a][i]; 15 f[a]=0; 16 mark[a]=1; 17 for(i=1;i<=n;i++) 18 { 19 min=max; 20 for(j=1;j<=n;j++) 21 { 22 if(!mark[j]&&f[j]<min) 23 { 24 min=f[j]; 25 k=j; 26 } 27 } 28 if(min==max) break; 29 mark[k]=1; 30 for(j=1;j<=n;j++) 31 { 32 if(!mark[j]&&f[k]+p[k][j]<f[j]) 33 f[j]=f[k]+p[k][j]; 34 } 35 } 36 if(f[b]==max) printf("-1\n"); 37 else 38 printf("%d\n",f[b]); 39 } 40 int main() 41 { 42 int i,j; 43 while(scanf("%d%d%d",&n,&a,&b)!=EOF) 44 { 45 int c; 46 for(i=1;i<=n;i++) 47 for(j=1;j<=n;j++) 48 p[i][j]=max; 49 for(i=1;i<=n;i++) 50 { 51 scanf("%d",&c); 52 if(c==0) continue;//第一次的時候忘了考慮c的取值,所以Time Limit Exceeded了一次 53 int d; 54 scanf("%d",&d); 55 p[i][d]=0; 56 c-=1; 57 while(c--) 58 { 59 scanf("%d",&d); 60 p[i][d]=1; 61 } 62 } 63 Dijkstra(); 64 } 65 return 0; 66 }
參考網絡資料:http://www.cppblog.com/abilitytao/archive/2009/07/07/89459.html
