1 条题解
-
0
我们计算以下数组: 表示涂完前 棵树,使得美感为 ,且第 棵树被涂成颜色 时所需要的最小油漆用量,并将所有初始值设为 。我们可以通过考虑两种情况来轻松计算这个 DP 数组:
-
当上一次使用的颜色与当前颜色相同时,那么如果当前树原本是未涂色的,我们应该用 来更新;否则直接用 ,因为涂色的美感保持不变。
-
当上一次使用的颜色与当前颜色不同时,那么我们应该用 (如果当前树未涂色)或 (如果当前树已涂色)来更新,其中 且 。理由类似。
如果当前树是未涂色的,我们需要遍历所有 种可能的颜色来涂它。
直接实现这个 DP 的时间复杂度为 ,对于本题而言已经足够通过。不过,我们可以通过避免在考虑上一次颜色时遍历所有颜色来优化到 ,即存储两个全局最小值。具体细节请参考代码。
时间复杂度: 或 。
#include <bits/stdc++.h> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/tree_policy.hpp> using namespace std; using namespace __gnu_pbds; #define fi first #define se second #define mp make_pair #define pb push_back #define fbo find_by_order #define ook order_of_key typedef long long ll; typedef pair<int,int> ii; typedef vector<int> vi; typedef long double ld; typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds; typedef set<int>::iterator sit; typedef map<int,int>::iterator mit; typedef vector<int>::iterator vit; const int N = 101; const int MOD = 1e9 + 7; const ll INF = ll(1e18); ll dp[N][N][N]; int c[N]; ll cost[N][N]; ll idx[N][N]; ll m1[N][N]; ll m2[N][N]; int main() { ios_base::sync_with_stdio(0); cin.tie(0); int n, m, k; cin >> n >> m >> k; for(int i = 1; i <= n; i++) { cin >> c[i]; } for(int i = 0; i <= n; i++) { for(int j = 0; j <= k; j++) { m1[i][j] = INF; m2[i][j] = INF; idx[i][j] = -1; for(int a = 0; a <= m; a++) { dp[i][j][a] = INF; } } } for(int i = 1; i <= n; i++) { for(int j = 1; j <= m; j++) { cin >> cost[i][j]; } } if(c[1] == 0) { for(int i = 1; i <= m; i++) { dp[1][1][i] = cost[1][i]; if(dp[1][1][i] <= m1[1][1]) { if(dp[1][1][i] == m1[1][1]) { idx[1][1] = -2; } else { idx[1][1] = i; } m2[1][1] = m1[1][1]; m1[1][1] = dp[1][1][i]; } else if(dp[1][1][i] <= m2[1][1]) { m2[1][1] = dp[1][1][i]; } } } else { dp[1][1][c[1]] = 0; m1[1][1] = 0; idx[1][1] = c[1]; } for(int i = 2; i <= n; i++) { for(int j = 1; j <= k; j++) { if(c[i] == 0) { for(int a = 1; a <= m; a++) { dp[i][j][a] = min(dp[i][j][a], dp[i-1][j][a] + cost[i][a]); ll tmp = INF; if(a == idx[i-1][j-1]) { tmp = m2[i-1][j-1]; } else { tmp = m1[i-1][j-1]; } dp[i][j][a] = min(dp[i][j][a], tmp + cost[i][a]); } } else { dp[i][j][c[i]] = min(dp[i][j][c[i]], dp[i-1][j][c[i]]); for(int b = 1; b <= m; b++) { if(b != c[i]) dp[i][j][c[i]] = min(dp[i][j][c[i]], dp[i-1][j-1][b]); } //cout << i << ' ' << j << ' ' << c[i] << ' ' << dp[i][j][c[i]] << '\n'; } for(int a = 1; a <= m; a++) { if(dp[i][j][a] <= m1[i][j]) { if(dp[i][j][a] == m1[i][j]) { idx[i][j] = -2; } else { idx[i][j] = a; } m2[i][j] = m1[i][j]; m1[i][j] = dp[i][j][a]; } else if(dp[i][j][a] <= m2[i][j]) { m2[i][j] = dp[i][j][a]; } } } } ll ans = INF; for(int i = 1; i <= m; i++) { ans = min(ans, dp[n][k][i]); } if(ans >= INF) ans = -1; cout << ans; } -
- 1
信息
- ID
- 6808
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 8
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者