三维dp&codeforce 369_2_C

三维dp&codeforce 369_2_C

标签: dp


codeforce 369_2_C

题意: 一排树,初始的时候有的有颜色,有的没有颜色,现在给没有颜色的树染色,给出n课树,用m种燃料涂,将相邻相同颜色的树划为一组,最后使得组数为k,并且所用燃料的量最小,给出了每棵树涂j种燃料的用量,如果存在这种涂法输出最小用量,不存在输出-1;

题解: 很容易看出是一个三维dp, dp[i][j][k] 表示处理到第i棵树,最后一棵树为颜色j,现在已经分成的组数为k的时候的最小用量
转移方程如果当前树初始有颜色,那么不能再涂其他颜色,则dp[i][j][k] = min(dp[i-1][j][k],dp[i-1][非j][k-1]);
如果现在树可以涂颜色那么有dp[i][j][k] = min(dp[i-1][j][k] + cost[j],dp[i-1][j][k-1] + cost[j]);
三维dp或者是普通dp要仔细想清楚的都是初始化,还是建议画图,直观的看,在当前的值计算前要先计算出哪些值,这样才可以知道转移的顺序和初始化的值,对于这个题,每次都是从上一次来的,所以对第一层的初始化就很有必要了,可以参考代码看具体如何初始化的,然后要注意是找最小值,所以一开始将所有状态初始化成INF

官方题解:
(它和我定义的有一点点区别,第二维和第三维反了,但是本质不影响)We compute the following array : dp[i][j][k] denoting the minimum amount of paint needed to color the first i trees such that it has beauty j and the i-th tree is colored by color k, and initialize all these values to ∞. We can compute this dp array easily by considering two cases :
1,When the last color used is equal to the current color, then we should compare it with dp[i - 1][j][k] + cost[i][k] if it was originally uncolored or dp[i - 1][j][k] otherwise, since the beauty of the coloring is the same.
2,When the last color used is different from the current color, then we should compare it with dp[i - 1][j - 1][l] + cost[i][k] or dp[i - 1][j - 1][l] for all 1 ≤ l ≤ m except when l is equal to the current color, by similar reasoning.
If the current tree is uncolored, we loop through all the m possible colors to color it.
Naively implementing this dp will give an O(nkm2), which is sufficient to pass for this problem. However, it is possible to optimize it into O(nkm) by avoiding iterating through all colors when considering the last color used and store two global minimums. See the code for more the details.
Time Complexity : O(nkm2) or O(nkm)

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<algorithm>
using namespace std;
#define ll long long
const ll INF = (ll)1e18;
const int N = 108;
ll dp[N][N][N];
int init[N];
ll cost[N][N];
int main()
{
	int n,m,c;
	while(~scanf("%d%d%d",&n,&m,&c))
	{
		for(int i = 1; i <= n; i++)
		{
			scanf("%d",&init[i]);
		}
		for(int i = 1; i <= n; i++)
		{
			for(int j = 1; j <= m; j++)
			{
				scanf("%I64d",&cost[i][j]);
			}
		}
		for(int i = 0; i <= n; i++)
			for(int j = 0; j <= m; j++)
				for(int k = 0; k <= c; k++)
					dp[i][j][k] = INF;
		if(init[1]==0)
		{
			for(int i = 1; i <= m; i++)
			{
				dp[1][i][1] = cost[1][i];
			}
		}
		else dp[1][init[1]][1] = 0;
		for(int i = 2; i <= n; i++)
		{
			for(int j = 1; j <= m; j++)
			{
				for(int k = 1; k <= c; k++)
				{
					if(init[i]!=0)
					{
						if(j!=init[i]) {
							dp[i][j][k] = INF;
							continue;
						}
						else {
							for(int u = 1; u <= m; u++)
							{
								if(u==j) dp[i][j][k] = min(dp[i-1][u][k],dp[i][u][k]);
								else if(u!=j) {
									dp[i][j][k] = min(dp[i][j][k],dp[i-1][u][k-1]);
								}
							}
						}
					}
					else if(init[i]==0)
					{
						for(int u = 1; u <= m; u++)
						{
							if(u==j){
								dp[i][j][k] = min(dp[i-1][j][k] + cost[i][j],dp[i][j][k]);
							}
							else if(u!=j)
							{
								dp[i][j][k] = min(dp[i-1][u][k-1] + cost[i][j],dp[i][j][k]);
							}
						}
					}
				}
			}
		}
		ll ans = INF;
		for(int i = 1; i <= m; i++)
		{
			ans = min(dp[n][i][c],ans);
		}
		if(ans==INF)
			puts("-1");
		else printf("%I64d\n",ans);
	}
	return 0;
}

posted on 2016-08-31 20:33  若流芳千古  阅读(415)  评论(0编辑  收藏  举报

导航