题目链接:这里
题意:给你n棵树,如果ci为0的话,那么这棵树就没有上色,否则这棵树就是ci颜色的。
相同颜色的树会被当成一段,现在你要恰好刷漆刷成k段,问你最小花费是多少。
把第i棵树刷漆刷成j颜色的花费为p[i][j]。
解法: dp[i][j][k]表示第i棵树,刷成了j颜色,当前有k段的最小花费是多少。直接暴力n^4的转移,稍加优化可以变成n^3的,这里显然还可以前缀和优化。
//CF 711C
#include <bits/stdc++.h>
using namespace std;
const int maxn = 105;
const long long inf = 1e15;
long long dp[2][maxn][maxn];//第i颗树,刷成了j颜色,当前有k段的最小花费
int n, m, K, c[maxn], p[maxn];
int now = 0, pre = 1;
long long ans = inf;
int main()
{
cin >> n >> m >> K;
for(int i = 1; i <= n; i++) cin >> c[i];
for(int j = 0; j <= m; j++){
for(int k = 0; k <= n; k++){
dp[now][j][k] = inf;
}
}
for(int i = 1; i <= m; i++) scanf("%d", &p[i]);
if(c[1] == 0){
for(int j = 1; j <= m; j++){
dp[now][j][1] = p[j];
}
}
else{
dp[now][c[1]][1] = 0;
}
for(int i = 2; i <= n; i++){
swap(pre, now);
for(int j = 0; j <= m; j++){
for(int k = 0; k <= n; k++){
dp[now][j][k] = inf;
}
}
for(int j = 1; j <= m; j++) cin >> p[j];
if(c[i] == 0){
for(int j = 1; j <= m; j++){
for(int k = 1; k <= n; k++){
dp[now][j][k] = min(dp[now][j][k], dp[pre][j][k] + p[j]);
for(int t = 1; t <= m; t++){
if(t == j) continue;
dp[now][j][k] = min(dp[now][j][k], dp[pre][t][k-1] + p[j]);
}
}
}
}
else{
for(int k = 1; k <= n; k++){
dp[now][c[i]][k] = min(dp[now][c[i]][k], dp[pre][c[i]][k]);
for(int t = 1; t <= m; t++){
if(t == c[i]) continue;
dp[now][c[i]][k] = min(dp[now][c[i]][k], dp[pre][t][k-1]);
}
}
}
}
for(int i = 1; i <= m; i++){
ans = min(ans, dp[now][i][K]);
}
if(ans == inf) puts("-1");
else printf("%lld\n", ans);
}