分析:
给出n棵树和m种颜色以及beauty值k,再给出n棵树的初始颜色,0就是没有涂色。再给出给第i棵树涂上第j种颜色需要的花费。beauty值的计算为树颜色集合的数目,比如给出7棵树颜色为2, 1, 1, 1, 3, 2, 2, 3, 1, 3,那么它的连续集合为{2}, {1, 1, 1}, {3}, {2, 2}, {3}, {1}, {3}一共7个集合,所以beauty值为7。题目要求怎么涂色才能使得达到目标beauty值的花费最小,输出最小花费,若不能达到,则输出-1。题解:
这是一道很明显的DP,我们可以设DP[i][j][k]来存储 用第i种颜色涂染第j棵树并且beauty值为k时的花费。转移方程可以这么想: 首先beauty值的计算只与当前涂色和前一棵树的涂色有关,若两者不同则当前beauty值增加,否则beauty值不变。然后给树涂色这一步操作看似会影响到之后涂色的beauty值,但是不会对之后状态涂色的花费产生影响,所以并没有后效性。
转移方程:
if(tree[i] == 0) //当前树没有被涂色
{
for(int a = 1; a <= m; a++)
{
DP[a][i][j] = min(DP[a][i][j], DP[a][i-1][j] + cost[i][a]); //先与上一棵树相同涂色的比较
for(int b = 1; b <= m; b++) //再遍历不同涂色的
{
if(b != a) DP[a][i][j] = min(DP[a][i][j], DP[b][i-1][j-1] + cost[i][a]);
}
}
}
else //当前树已经被涂色
{
DP[tree[i]][i][j] = min(DP[tree[i]][i][j], DP[tree[i]][i-1][j]); //相同涂色
for(int b = 1; b <= m; b++) //遍历不同涂色
{
if(b != tree[i]) DP[tree[i]][i][j] = min(DP[tree[i]][i][j], DP[b][i-1][j-1]);
}
}
- AC代码:
/*************************************************************************
> File Name: test.cpp
> Author: Akira
> Mail: qaq.febr2.qaq@gmail.com
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <ctime>
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
using namespace std;
#define MaxN 100000
#define MaxM MaxN*10
const LL INF = LL(1e18);
#define bug cout<<88888888<<endl;
int n,m,k;
int tree[110];
LL ans;
LL cost[110][110];
LL DP[110][110][110]; //用第i种颜色涂第j颗树,beauty为k的花费
LL solve()
{
ans = INF;
if(tree[1]!=0)
{
DP[tree[1]][1][1] = 0;
}
else
{
for(int i=1;i<=m;i++)
{
DP[i][1][1] = cost[1][i];
}
}
for(int i = 2; i <= n; i++)
{
for(int j = 1; j <= k; j++)
{
if(tree[i] == 0)
{
for(int a = 1; a <= m; a++)
{
DP[a][i][j] = min(DP[a][i][j], DP[a][i-1][j] + cost[i][a]);
for(int b = 1; b <= m; b++)
{
if(b != a) DP[a][i][j] = min(DP[a][i][j], DP[b][i-1][j-1] + cost[i][a]);
}
}
}
else
{
DP[tree[i]][i][j] = min(DP[tree[i]][i][j], DP[tree[i]][i-1][j]);
for(int b = 1; b <= m; b++)
{
if(b != tree[i]) DP[tree[i]][i][j] = min(DP[tree[i]][i][j], DP[b][i-1][j-1]);
}
}
}
}
for(int i = 1; i <= m; i++)
{
ans = min(ans, DP[i][n][k]);
}
if(ans >= INF) return -1;
else return ans;
}
int main()
{
while( ~scanf("%d%d%d", &n, &m, &k))
{
for(int i=0;i<=m;i++)
for(int j=0;j<=n;j++)
for(int l=0;l<=k;l++)
DP[i][j][l] = INF;
for(int i=1;i<=n;i++)
scanf("%d", &tree[i]);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%lld", &cost[i][j]);
}
}
cout << solve() << endl;
}
//system("pause");
}