简单说就是一道最短路+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的时候判断一下这个港口是否可走就行。
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 }