(DP002)(滚动数组)洛谷P1541乌龟棋

一、算法分析

寒假前曾信誓旦旦说要多练DP,还立了帖子要做一百道,现在继续第二道吧。。。
题目很好理解,状态的保存和转移都比较直观,刚开始打算在状态的DP数组加一个步数维度,表示走到第几个格子,但是这样就成了五维数组了,显然会爆空间。后来发现没有必要,当前格子由当前使用的牌的数目完全导出。所以平时解DP问题时,开始可能想到的状态空间很复杂,这个没关系,但是在实现之前一定要进行优化,考察各个维度是否是线性无关的。
分析到这里这个问题已经得到了解决,(详见代码)。但是如果本题对于空间的要求更加严格的话,事实上我们还可以进行一下滚动数组优化,再压缩一个维度。(其实这个滚动数组优化这道题是在别人的题解中发现的思想,但是别人的题解的写法笔者看不明白,所以就做了几道其它的滚动数组优化的DP,再用自己的写法写了本题的滚动数组优化,个人感觉相对好懂一些吧。)
其他大佬的题解直接把第一个维度压掉了,笔者的代码是把第一个维度压到2。

二、代码及注释

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m;
const int maxn=42;
int a[355];
int b[maxn];
int ans;
int f[2][maxn][maxn][maxn];   //表示每种牌用了几张,对第一个维度进行滚动数组优化 
int cnt[5];
int main(){

	scanf("%d%d",&n,&m);
	int x;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]);//每个位置的得分 
	for(int i=1;i<=m;i++){
		scanf("%d",&x);
		cnt[x]++;                 //记录每种卡片多少张 
	}
	f[0][0][0][0]=a[1];         //起点 
	for(int i=0;i<=cnt[1];i++){
		int pos=i&1;              //滚动数组 
		int pre=(i&1)^1;
		for(int j=0;j<=cnt[2];j++)
		  for(int k=0;k<=cnt[3];k++)
		    for(int l=0;l<=cnt[4];l++){
		    	int pp=a[i+j*2+k*3+l*4+1];//当前位置得分 
		    	if(i) f[pos][j][k][l]=max(f[pos][j][k][l],f[pre][j][k][l]+pp);
		    	if(j) f[pos][j][k][l]=max(f[pos][j][k][l],f[pos][j-1][k][l]+pp);
				  if(k) f[pos][j][k][l]=max(f[pos][j][k][l],f[pos][j][k-1][l]+pp);
				  if(l) f[pos][j][k][l]=max(f[pos][j][k][l],f[pos][j][k][l-1]+pp);
				}  
	}
	printf("%d",max(f[0][cnt[2]][cnt[3]][cnt[4]],f[1][cnt[2]][cnt[3]][cnt[4]]));
	return 0;
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值