题目链接:这里
题意:给你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);
}