区间dp 石子合并 切木条等 持续更新ing

石子合并(相邻) 切木条是互为逆过程 这里只写一种
对于每堆石子,我们可以想到,此处是由2堆石子合并,所以最终最优解肯定是由两个局部最优解的加上整体的和求得。
状态转移方程:dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[i][j]); 表示从i到j的这段区间 是由合成这两个小区间的代价之和 加上合成大区间的代价 与dp[i][j]取最小。

#include<iostream>
#include<algorithm>
#include<string.h>
#define inf 0x3f3f3f3f
using namespace std;
int main()
{
	int dp1[205][205],dp2[205][205],n,sum[205];
	while(cin>>n)
	{
		memset(dp1,inf,sizeof(dp1));
		memset(dp2,0,sizeof(dp2));
		memset(sum,0,sizeof(sum));
		for(int i=0;i<205;i++)
			dp1[i][i]=0;
		for(int i=1;i<=n;i++)
		{
			int temp;
			cin>>temp;
			sum[i]=sum[i-1]+temp;
		}
		for(int len=1;len<n;len++)
		{
			for(int i=1;i+len<=n;i++)
			{
				int j=i+len;
				for(int k=i;k<j;k++)
					dp1[i][j]=min(dp1[i][j],dp1[i][k]+dp1[k+1][j]+sum[j]-sum[i-1]),dp2[i][j]=max(dp2[i][j],dp2[i][k]+dp2[k+1][j]+sum[j]-sum[i-1]);
			}
		}
		cout<<dp1[1][n]<<" "<<dp2[1][n]<<endl;
	}
	return 0;	
} 

POJ 1651 Multiplication Puzzle
区间dp都差不多,主要就是一些细节问题,这个题目需要注意的是两个初始化,在代码中标注了,注释掉的那个地方不对。
状态转移方程:
表示从第i个数到第j个数抽取完后的最小值。一开始初始化为3个数,就只有3个数相乘。后面长度从3增加到n,则状态转移方程为dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[i]*a[k]*a[j])(i<k<j)其中k表示在i…j中最后抽的牌是a[k].

#include<iostream>
#include<cmath>
#include<vector>
#include<cstdio> 
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int main()
{
	int dp[205][205],n,a[205];
	while(cin>>n)
	{
		//memset(dp,inf,sizeof(dp));
		for(int i=1;i<=n;i++)
			cin>>a[i];
		for(int i=1;i<n-1;i++)
		{
			dp[i][i+2]=a[i]*a[i+1]*a[i+2];   //初始化3个数相乘 ① 
		}
		for(int len=3;len<n;len++)
		{
			for(int i=1;i+len<=n;i++)
			{
				int j=i+len;
				dp[i][j]=inf;//② 初始化
				for(int k=i+1;k<j;k++)
					dp[i][j]=min(dp[i][j],dp[i][k]+dp[k][j]+a[k]*a[i]*a[j]);
			}
		}
		cout<<dp[1][n]<<endl; 
	}
	return 0;	
} 

lightOJ 1422
题意:小灰灰参加圣诞节的一些派对,并且需要穿上对应派对的衣服,所以他需要多次换衣服,为了方便,他可以选择脱掉一些衣服或者穿上新衣服,比如说,他穿着超人的衣服,外面又穿着死侍的衣服,当他要参加超人服装派对时,他可以选择脱掉死侍的衣服(因为死侍衣服的里面有超人的衣服),或者他可以在穿一件超人的衣服,小灰灰是个爱干净的人,当他脱下死侍的衣服后,如果需要再穿死侍的衣服,他会选择再穿一件新的。(如果他先穿A衣服,又穿上B衣服,再穿一件C衣服,如果他想让最外面的衣服是A,他可以选择直接穿一件A,或者先把C脱掉,再把B脱掉)。
思路:
区间dp
穿新的 dp[i][j]=dp[i][j-1]+1
不穿新的,即脱掉外面的几层漏出当前需要的来,那么需要从i到j-1里有一个k a[k]=a[j],
那么dp[i][k]+dp[k+1][j-1]

#include<iostream>
#include<cmath>
#include<vector>
#include<cstdio> 
#include<cstring>
#include<algorithm>
#define ll long long
#define inf 0x3f3f3f3f
using namespace std;
int main()
{
	int dp[205][205],n,a[205],t;
	cin>>t;
	for(int tt=1;tt<=t;tt++)
	{
		cin>>n;
		memset(dp,0,sizeof(dp));
		for(int i=0;i<205;i++)
			dp[i][i]=1;
		for(int i=1;i<=n;i++)
			cin>>a[i];
		for(int len=1;len<n;len++)
		{
			for(int i=1;i+len<=n;i++)
			{
				int j=i+len;
				dp[i][j]=dp[i][j-1]+1;
				for(int k=i;k<j;k++)
					if(a[j]==a[k])
						dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j-1]);
			}
		}
		printf("Case %d: %d\n",tt,dp[1][n]);
	}
	return 0;	
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值