[ZJOI2006]物流运输 DP 最短路
题解:
设f[i]表示到第i天的代价,cost[i][j]表示第i天到第j天采取同一种方案的最小代价。那么转移就很明显了,直接$n^2$枚举即可。
所以问题就变成了怎么获取cost数组。因为i到j都采取同一种方案,因此这种方案不能经过在i到j这些天出现故障的码头,因为要求的是最小代价,因此直接跑最短路,然后注意判断一下不能经过在i到j会出现故障的码头即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define R register int 4 #define AC 110 5 #define ac 450 6 int n, m, k, e, d; 7 int Head[AC], date[ac], Next[ac], len[ac], tot; 8 int dis[AC], f[AC], cost[AC][AC], sum[AC][AC];//sum[天][码头] 9 bool z[AC]; 10 11 struct cmp{ 12 bool operator () (int a, int b) 13 { 14 return dis[a] < dis[b]; 15 } 16 }; 17 18 priority_queue<int, vector<int>, cmp> q; 19 20 inline int read() 21 { 22 int x = 0;char c = getchar(); 23 while(c > '9' || c < '0') c = getchar(); 24 while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); 25 return x; 26 } 27 28 inline void add(int f, int w, int S) 29 { 30 date[++tot] = w, Next[tot] = Head[f], Head[f] = tot, len[tot] = S; 31 date[++tot] = f, Next[tot] = Head[w], Head[w] = tot, len[tot] = S; 32 } 33 34 void upmin(int &a, int b) 35 { 36 if(b < a) a = b; 37 } 38 39 void spfa(int l, int r) 40 { 41 int x, now; 42 memset(dis, 127, sizeof(dis)); 43 dis[1] = 0; 44 q.push(1), z[1] = true; 45 while(!q.empty()) 46 { 47 x = q.top(); 48 q.pop(); 49 z[x] = false; 50 for(R i = Head[x]; i; i = Next[i]) 51 { 52 now = date[i]; 53 if(sum[r][now] - sum[l - 1][now]) continue;//如果这几天中故障过就不能用 54 if(dis[now] > dis[x] + len[i]) 55 { 56 dis[now] = dis[x] + len[i]; 57 if(!z[now]) q.push(now), z[now] = true; 58 } 59 } 60 } 61 if(dis[m] != dis[0]) cost[l][r] = dis[m] * (r - l + 1); 62 else cost[l][r] = dis[m];//防爆 63 } 64 65 void pre() 66 { 67 int a, b, c; 68 n = read(), m = read(), k = read(), e = read(); 69 for(R i = 1; i <= e; i ++) 70 { 71 a = read(), b = read(), c = read(); 72 add(a, b, c); 73 } 74 d = read(); 75 for(R i = 1; i <= d; i ++) 76 { 77 a = read(), b = read(), c =read(); 78 for(R j = b; j <= c; j ++) sum[j][a] = 1; 79 } 80 for(R i = 1; i <= m; i ++)//枚举码头 81 for(R j = 1; j <= n; j ++) 82 sum[j][i] += sum[j - 1][i]; 83 } 84 85 void work() 86 { 87 for(R i = 1; i <= n; i ++) 88 for(R j = i; j <= n; j ++) spfa(i, j); 89 memset(f, 127, sizeof(f)); 90 f[0] = -k;//因为第一天不用承受换方案的代价 91 for(R i = 1; i <= n; i ++)//枚举天数 92 for(R j = 0; j < i; j ++)//枚举上一段的结尾 93 upmin(f[i], f[j] + cost[j + 1][i] + k); 94 printf("%d\n", f[n]); 95 } 96 97 int main() 98 { 99 // freopen("in.in", "r", stdin); 100 pre(); 101 work(); 102 // fclose(stdin); 103 return 0; 104 }