1. 程式人生 > >[倍增][最短路-Floyd][dp]

[倍增][最短路-Floyd][dp]

輸出 有向圖 %d pan 自然 公司 ems AC 說明

題目描述

小A的工作不僅繁瑣,更有苛刻的規定,要求小A每天早上在6:00之前到達公司,否則這個月工資清零。可是小A偏偏又有賴床的壞毛病。於是為了保住自己的工資,小A買了一個十分牛B的空間跑路器,每秒鐘可以跑2^k千米(k是任意自然數)。當然,這個機器是用longint存的,所以總跑路長度不能超過maxlongint千米。小A的家到公司的路可以看做一個有向圖,小A家為點1,公司為點n,每條邊長度均為一千米。小A想每天能醒地盡量晚,所以讓你幫他算算,他最少需要幾秒才能到公司。數據保證1到n至少有一條路徑。

輸入輸出格式

輸入格式:

第一行兩個整數n,m,表示點的個數和邊的個數。

接下來m行每行兩個數字u,v,表示一條u到v的邊。

輸出格式:

一行一個數字,表示到公司的最少秒數。

輸入輸出樣例

輸入樣例#1:
4 4
1 1
1 2
2 3
3 4
輸出樣例#1:
1

說明

【樣例解釋】

1->1->2->3->4,總路徑長度為4千米,直接使用一次跑路器即可。

【數據範圍】

50%的數據滿足最優解路徑長度<=1000;

100%的數據滿足n<=50,m<=10000,最優解路徑長度<=maxlongint。

題解

  • 這道題目求的是從1號點到n號點最少要幾秒到達
  • 我們可以看到這個跑路器,每秒跑2^k條邊(每條邊1km),
  • 用一個參數k表示2^k,G[i][j][k]代表從i到j是否存在一條長度為2^k的路徑
  • 再用dis數組來記錄兩點之間需要用多久到達
  • 這樣我們可以用G來保存所有的邊,並且進行預處理
  • 然後把所有一秒能到的兩個點之間都連上邊,並把距離相應調整為1
  • 那麽我們就把所有一秒能到的點之間都鋪上了邊
  • 最後就要求出兩點之間的最短路,跑一遍Floyd

代碼

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int dis[60][60],n,m,x,y;
 4 bool G[60][60][65]={false};
 5
int main() 6 { 7 memset(dis,10,sizeof(dis)); 8 scanf("%d%d",&n,&m); 9 for(int i=1;i<=m;i++) 10 { 11 scanf("%d%d",&x,&y); 12 dis[x][y]=1; 13 G[x][y][0]=true; 14 } 15 for(int k=1;k<=64;k++) 16 for(int i=1;i<=n;i++) 17 for(int t=1;t<=n;t++) 18 for(int j=1;j<=n;j++) 19 if(G[i][t][k-1]&&G[t][j][k-1]) 20 { 21 G[i][j][k]=true; 22 dis[i][j]=1; 23 } 24 for(int k=1;k<=n;k++) 25 for(int i=1;i<=n;i++) 26 for(int j=1;j<=n;j++) 27 dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]); 28 printf("%d",dis[1][n]); 29 return 0; 30 }

[倍增][最短路-Floyd][dp]