嘟嘟嘟

 

简单说就是一道最短路+dp。

令dp[i] 表示到第 i 天最小的总成本,每一次 j 从 i 到1枚举,得到dp方程 dp[i] = min(dp[i], dp[j - 1] + cost * (i - j + 1) + k)。其中 cost 表示从 j 到 i 这几天都可以走的最短路,因此在第 j 天要改变一次线路,所以加一次k。这时可定有人会问,若果第 j 天之前和第 j 天开始走的路径是一样的,那不就不应该加k了吗?别忘了,j 是枚举的,因此这个状况会在 j' < j 的时候考虑到。

然后cost就可以用最短路来求,因为没有负边权,所以用dijkstra就行(坚决不用spfa),然后跑dij的时候判断一下这个港口是否可走就行。

 

[ZJOI2006]物流运输_C  教程[ZJOI2006]物流运输_编程开发_02
  1 #include<cstdio>
  2 #include<iostream>
  3 #include<algorithm>
  4 #include<cmath>
  5 #include<cstring>
  6 #include<cstdlib>
  7 #include<cctype>
  8 #include<stack>
  9 #include<queue>
 10 #include<vector>
 11 using namespace std;
 12 #define enter puts("")
 13 #define space putchar(' ')
 14 #define Mem(a) memset(a, 0, sizeof(a))
 15 typedef long long ll;
 16 typedef double db;
 17 const int INF = 0x3f3f3f3f;
 18 const db eps  =1e-8;
 19 const int maxn = 25;
 20 const int max_day = 105;
 21 inline ll read()
 22 {
 23     ll ans = 0;
 24     char ch = getchar(), last = ' ';
 25     while(!isdigit(ch)) {last = ch; ch = getchar();}
 26     while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
 27     if(last == '-') ans = -ans;
 28     return ans;
 29 }
 30 inline void write(ll x)
 31 {
 32     if(x < 0) putchar('-'), x = -x;
 33     if(x >= 10) write(x / 10);
 34     putchar(x % 10 + '0');
 35 }
 36 
 37 int n, m, k, e;
 38 vector<int> v[maxn], c[maxn];
 39 bool gg[maxn][max_day];
 40 int dp[max_day];
 41 bool vis[maxn];
 42 
 43 int dis[maxn];
 44 bool in[maxn];
 45 #define pr pair<int, int>
 46 #define mp make_pair
 47 int dijkstra()
 48 {
 49     Mem(in);
 50     for(int i = 1; i <= m; ++i) dis[i] = INF;
 51     priority_queue<pr, vector<pr>, greater<pr> > q;
 52     dis[1] = 0; 
 53     q.push(mp(dis[1], 1));
 54     while(!q.empty())
 55     {
 56         pr node = q.top(); q.pop(); 
 57         int now = node.second;
 58         if(in[now]) continue;
 59         in[now] = 1;
 60         for(int i = 0; i < (int)v[now].size(); ++i)
 61         {
 62             if(vis[v[now][i]]) continue;        //该港口被封锁 
 63             if(dis[now] + c[now][i] < dis[v[now][i]])
 64             {
 65                 dis[v[now][i]] = dis[now] + c[now][i];
 66                 q.push(mp(dis[v[now][i]], v[now][i]));
 67             }
 68         }
 69     }
 70     return dis[m];
 71 }
 72 
 73 int main()
 74 {
 75     n = read(); m = read(); k = read(); e = read();
 76     for(int i = 1; i <= e; ++i)
 77     {
 78         int x = read(), y = read(), co = read();
 79         v[x].push_back(y); c[x].push_back(co);
 80         v[y].push_back(x); c[y].push_back(co);
 81     }
 82     int d = read();
 83     for(int i = 1; i <= d; ++i)
 84     {
 85         int p = read(), L = read(), R = read();
 86         for(int j = L; j <= R; ++j) gg[p][j] = 1;
 87     }
 88     for(int i = 1; i <= n; ++i) dp[i] = INF;
 89     dp[0] = -k;        //第一天不需要换路,但因为dp式式每一次都要换路的,所以dp[0]初值要设为-k 
 90     for(int i = 1; i <= n; ++i)
 91     {
 92         Mem(vis);
 93         for(int j = i; j > 0;--j)
 94         {
 95             for(int w = 1; w <= m; ++w) vis[w] |= gg[w][j];        //注意用 |,就表示有的港口这几天都会被封锁 
 96             int cost = dijkstra();
 97             if(cost == INF) continue;        //可能这几天一条路都走不出来(因为题中只保证一天有路可走) 
 98             dp[i] = min(dp[i], dp[j - 1] + cost * (i - j + 1) + k);
 99         }
100     }
101     write(dp[n]); enter;
102     return 0;
103 }
View Code