Codeforces Round #369 (Div. 2) C. Coloring Trees(dp)
题目链接
题意:有n棵树,m种颜料,要求现在要给这些树涂上颜料,最后涂成k段(连续颜色相同划为一段如2, 1, 1, 1, 3, 2, 2, 3, 1, 3是7段),有些树已经涂了,则不涂,其余的树只能涂一次,输入n个数(每个数为0~m),0表示还没有涂,1~m表示已经涂了哪种颜料。接下来输入n行m列,表示每棵树涂成每种颜色所要的颜料量。现在要把所有树都涂上颜料涂成k段,求最少要用的颜料量;
dp[i][j][k]表示第i颗树涂第j种颜色分成k段最少所需的颜料数
分情况考虑
1 .arr[i]==0即可涂色时,枚举颜色数和上一层的颜色数
2.arr[i]!=0不可涂色 ,只枚举上一层颜色数即可
当上一层颜色数相同时,段数不变,否则段数增一,也就是上一层的段数少一
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define inf 199999999999
const int N=110;
ll dp[N][N][N];
ll arr[N];
ll cost[N][N];
int main()
{
#ifdef LOCAL_DEFINE
freopen("D://rush.txt", "r", stdin);
#endif
ios::sync_with_stdio(false),cin.tie(0);
ll n,m,q;
cin>>n>>m>>q;
for(int i=1;i<=n;i++)
cin>>arr[i];
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
cin>>cost[i][j];
}
memset(dp,1,sizeof dp);
if(arr[1])
{
dp[1][arr[1]][1]=0;
}
else
{
for(int j=1;j<=m;j++)
dp[1][j][1]=cost[1][j];
}
for(int i=2;i<=n;i++)
{
if(arr[i])
{
for(int k=1;k<=i;k++)
{
for(int pre=1;pre<=m;pre++)
{
if(pre==arr[i])
dp[i][arr[i]][k]=min(dp[i][arr[i]][k],dp[i-1][pre][k]);
else
dp[i][arr[i]][k]=min(dp[i][arr[i]][k],dp[i-1][pre][k-1]);
}
}
}
else
{
for(int j=1;j<=m;j++)
{
for(int k=1;k<=i;k++)
{
for(int pre=1;pre<=m;pre++)
{
if(pre==j)
dp[i][j][k]=min(dp[i][j][k],dp[i-1][pre][k]+cost[i][j]);
else
dp[i][j][k]=min(dp[i][j][k],dp[i-1][pre][k-1]+cost[i][j]);
}
}
}
}
}
ll ans=inf;
for(int i=1;i<=m;i++)
ans=min(ans,dp[n][i][q]);
if(ans==inf) cout<<-1<<endl;
else cout<<ans<<endl;
return 0;
}