题目大意:公园里有 n n n棵树,每棵树有颜色 a i a_i ai,也可能没涂颜色,现在有 m m m种颜料,可以给没颜色的树涂颜色,花费以矩阵的形式给出: a [ i ] [ j ] a[i][j] a[i][j]表示第 i i i棵树涂颜色 j j j的花费。连续相同的一段颜色贡献为 1 1 1,求所有树贡献恰好为 k k k的最小花费。
卡了半天的简单DP题。数据范围 100 100 100, O ( n 4 ) O(n^4) O(n4)可写。设 d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]为前 i i i颗树,第 i i i颗为 j j j颜色,贡献为 k k k的最小花费。
AC代码:
int n, m, k, ans = INF;
int col[110];
int mp[110][110];
long long dp[110][110][110]; //dp[i][j][l]表示第i棵树用颜色j产生l贡献的最小花费
int main()
{
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= n; i++)
scanf("%d", &col[i]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &mp[i][j]);
fill(dp[0][0], dp[0][0] + 110 * 110 * 110, INF); //初始化
if (col[1])
dp[1][col[1]][1] = 0;
else
for (int j = 1; j <= m; j++)
dp[1][j][1] = mp[1][j];
for (int i = 2; i <= n; i++)
{
if (!col[i]) //如果可以涂颜色
{
for (int j = 1; j <= m; j++)
for (int l = 1; l <= k; l++)
for (int j2 = 1; j2 <= m; j2++)
if (j2 != j) //和前一颗不同色
dp[i][j][l] = min(dp[i][j][l], dp[i - 1][j2][l - 1] + mp[i][j]);
else //和前一颗同色
dp[i][j][l] = min(dp[i][j][l], dp[i - 1][j2][l] + mp[i][j]);
}
else //不能涂颜色
{
for (int j = 1; j <= m; j++)
for (int l = 1; l <= k; l++)
if (col[i] == j) //和前一颗同色
dp[i][col[i]][l] = min(dp[i][col[i]][l], dp[i - 1][j][l]);
else //和前一颗不同色
dp[i][col[i]][l] = min(dp[i][col[i]][l], dp[i - 1][j][l - 1]);
}
}
long long ans = INF;
for (int i = 1; i <= m; i++) //枚举最后一棵树的颜色
ans = min(ans, dp[n][i][k]);
printf("%lld\n", ans == INF ? -1 : ans);
return 0;
}