1. 程式人生 > 實用技巧 >牛客多校五 A.portal【dp|Floyd】

牛客多校五 A.portal【dp|Floyd】

題意:

  在一個n點m邊的帶權無向圖上從ai走到bi做k個任務,求最小花費。

  可以在當點隨時建立一個傳送門,或者關閉任一點一個傳送門,傳送門數量不大於兩個

  通過傳送門從u傳送到v花費為0

做法:

  通過Floyd預處理出每兩個點之間的距離

  考慮動態規劃來解決最小花費問題

  f[i][j] 表示完成i個任務時,當前位置在a[i]上,傳送門在j處的最小花費

  轉移有:

  1.直接從a[i]走到a[i+1]

  2.列舉走到a[i+1]之後,傳送門的位置變為了哪個節點,設這個節點是q。第二種轉移是從a[i]走到q,在q設定傳送門,從q傳送到p,再從p走到a[i+1]

   3.第三種轉移是從a[i]傳送到p,從p走到q,在q設定傳送門,最後從q走到a[i+1]

  最後遍歷一遍完成k個任務後,取傳送門在1~n的最小花費即可

CODE

 1 #include <bits/stdc++.h>
 2 #define dbug(x) cout << #x << "=" << x << endl
 3 #define eps 1e-8
 4 #define pi acos(-1.0)
 5  
 6 using namespace std;
 7 typedef long long LL;
 8  
 9 const int inf = 0x3f3f3f3f;
10  
11 template<class
T>inline void read(T &res) 12 { 13 char c;T flag=1; 14 while((c=getchar())<'0'||c>'9')if(c=='-')flag=-1;res=c-'0'; 15 while((c=getchar())>='0'&&c<='9')res=res*10+c-'0';res*=flag; 16 } 17 18 const int maxn = 1e3 + 7; 19 20 int n, m, k; 21 LL a[maxn]; 22 LL f[maxn][maxn];
23 24 LL dis[maxn][maxn]; 25 26 int main() 27 { 28 memset(dis, inf, sizeof(dis)); 29 read(n); read(m); read(k); 30 for ( int i = 1; i <= n; ++i ) { 31 dis[i][i] = 0; 32 } 33 for ( int i = 1; i <= m; ++i ) { 34 int u, v, w; 35 read(u); read(v); read(w); 36 dis[u][v] = dis[v][u] = min(dis[u][v], min(1ll * w, dis[v][u])); 37 } 38 for ( int k = 1; k <= n; ++k ) { 39 for ( int i = 1; i <= n; ++i ) { 40 for ( int j = 1; j <= n; ++j ) { 41 if(i == j) { 42 dis[i][j] = dis[j][i] = 0; 43 } 44 else { 45 if(dis[i][k] + dis[k][j] < dis[i][j]) { 46 dis[i][j] = dis[i][k] + dis[k][j]; 47 } 48 } 49 } 50 } 51 } 52 memset(f, inf, sizeof(f)); 53 // for ( int i = 1; i <= n; ++i ) { 54 // f[1][i] = inf; 55 // } 56 int p = k << 1; 57 for ( int i = 1; i <= p; ++i ) { 58 read(a[i]); 59 } 60 for ( int i = 1; i <= n; ++i ) { 61 f[1][i] = INT64_MAX; 62 } 63 f[0][1] = 0; 64 a[0] = 1; 65 for ( int i = 1; i <= p; ++i ) { 66 for ( int j = 1; j <= n; ++j ) { 67 f[i][j] = min(f[i][j], f[i - 1][j] + dis[a[i - 1]][a[i]]); 68 f[i][j] = min(f[i][j], f[i - 1][j] + dis[j][a[i]]); 69 for ( int z = 1; z <= n; ++z ) { 70 f[i][z] = min(f[i][z], f[i - 1][j] + dis[a[i - 1]][z] + dis[z][a[i]]); 71 f[i][z] = min(f[i][z], f[i - 1][j] + dis[a[i - 1]][z] + dis[j][a[i]]); 72 f[i][z] = min(f[i][z], f[i - 1][j] + dis[j][z] + dis[z][a[i]]); 73 } 74 } 75 } 76 // for ( int i = 1; i <= p; ++i ) { 77 // for ( int j = 1; j <= n; ++j ) { 78 // printf("f[%d][%d]:%d\n",i, j, f[i][j]); 79 // } 80 // } 81 LL ans = INT64_MAX; 82 for ( int i = 1; i <= n; ++i ) { 83 ans = min(1ll * f[p][i], ans); 84 } 85 cout << ans << endl; 86 return 0; 87 }