【题目链接】
【思路要点】
- 显然,两次变换线路之间所走的路一定是所能走的最短路。
- 记\(Cost_{i,j}\)表示第\(i\)天至第\(j\)天均能走的路中最短路的长度。
- 那么可以设计简单DP,用\(F_{i}\)表示第一天到底\(i\)天的最小花费,那么显然有转移方程:$$F_{i}=min_{j=0}^{i-1}\{Cost_{j-1,i}+k+F_{j}\}$$
- 若采用\(Floyd\)算法求解最短路,时间复杂度为\(O(N^{2}*M^{3})\)。
【代码】
#include<bits/stdc++.h> using namespace std; #define MAXD 105 #define MAXN 25 #define MAXM 1005 #define INF 1e9 template <typename T> void read(T &x) { x = 0; int f = 1; char c = getchar(); for (; !isdigit(c); c = getchar()) if (c == '-') f = -f; for (; isdigit(c); c = getchar()) x = x * 10 + c - '0'; x *= f; } int d, n, cost, m, q; int x[MAXM], y[MAXM], z[MAXM], dp[MAXD]; bool mark[MAXN][MAXD], disable[MAXN]; void chkmin(int &x, int y) { x = min(x, y); } int calc() { static int dist[MAXN][MAXN]; for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) if (i == j) dist[i][j] = 0; else dist[i][j] = INF; for (int i = 1; i <= m; i++) if (!disable[x[i]] && !disable[y[i]]) { chkmin(dist[x[i]][y[i]], z[i]); chkmin(dist[y[i]][x[i]], z[i]); } for (int k = 1; k <= n; k++) for (int i = 1; i <= n; i++) for (int j = 1; j <= n; j++) chkmin(dist[i][j], dist[i][k] + dist[k][j]); return dist[1][n]; } int main() { read(d), read(n), read(cost), read(m); for (int i = 1; i <= m; i++) read(x[i]), read(y[i]), read(z[i]); read(q); for (int i = 1; i <= q; i++) { int x, y, z; read(x), read(y), read(z); for (int j = y; j <= z; j++) mark[x][j] = true; } for (int i = 1; i <= d; i++) dp[i] = INF; dp[0] = -cost; for (int i = 1; i <= d; i++) { memset(disable, false, sizeof(disable)); for (int j = i; j <= d; j++) { for (int k = 1; k <= n; k++) disable[k] |= mark[k][j]; int tmp = calc(); if (tmp < INF) chkmin(dp[j], dp[i - 1] + cost + tmp * (j - i + 1)); } } printf("%d\n", dp[d]); return 0; }