[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 }

 

posted @ 2018-09-06 14:07  ww3113306  阅读(131)  评论(0编辑  收藏  举报
知识共享许可协议
本作品采用知识共享署名-非商业性使用-禁止演绎 3.0 未本地化版本许可协议进行许可。