【dp】乌龟棋

Luogu P1541

题目:

从1点起,用拥有的1,2,3,4牌(消耗)移动,最后到达终点,求经过点的权值最大(包括起点)

题解:

应该算是一个基础入门题吧,但我还是想写下
首先想到的DP:
d p [ i ] [ s 1 ] [ s 2 ] [ s 3 ] [ s 4 ] 表 示 用 了 s 1 张 1 , s 2 张 2 , s 3 张 3 , s 4 张 4 后 到 达 i 点 的 最 大 值 dp[i][s1][s2][s3][s4]表示用了s1张1,s2张2,s3张3,s4张4后到达i点的最大值 dp[i][s1][s2][s3][s4]s11,s22,s33,s44i
然鹅,算下来空间和时间都会炸掉
于是可以发现 i , s 4 , s 3 , s 2 固 定 后 , s 1 是 可 以 算 出 来 的 i,s4,s3,s2固定后,s1是可以算出来的 i,s4,s3,s2s1
于是变成了
d p [ i ] [ s 2 ] [ s 3 ] [ s 4 ] dp[i][s2][s3][s4] dp[i][s2][s3][s4]空间时间就刚好过了qwq
然后刷表法走一遭,快乐地输出 d p [ n ] [ t 2 ] [ t 3 ] [ t 4 ] dp[n][t_2][t_3][t_4] dp[n][t2][t3][t4],AC了qwq

#include<bits/stdc++.h>
using namespace std;
const int N=355,M=45;
int n,m;
int a[N],t[5];
int dp[N][M][M][M];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	scanf("%d",&a[i]);
	for(int x,i=1;i<=m;i++)
	scanf("%d",&x),t[x]++;
	dp[1][0][0][0]=a[1];
	for(int i=1;i<=n;i++)
	{
		for(int s4=0;s4<=t[4];s4++)
		{
			for(int s3=0;s3<=t[3];s3++)
			{
				for(int s2=0;s2<=t[2];s2++)
				{
					int s1=i-4*s4-3*s3-2*s2-1;if(s1<0)break;if(s1>t[1])continue;
					if(s1+1<=t[1])dp[i+1][s2][s3][s4]=max(dp[i][s2][s3][s4]+a[i+1],dp[i+1][s2][s3][s4]);
					if(s2+1<=t[2])dp[i+2][s2+1][s3][s4]=max(dp[i][s2][s3][s4]+a[i+2],dp[i+2][s2+1][s3][s4]);
					if(s3+1<=t[3])dp[i+3][s2][s3+1][s4]=max(dp[i][s2][s3][s4]+a[i+3],dp[i+3][s2][s3+1][s4]);
					if(s4+1<=t[4])dp[i+4][s2][s3][s4+1]=max(dp[i][s2][s3][s4]+a[i+4],dp[i+4][s2][s3][s4+1]);
				}
			}
		}
	}
	printf("%d",dp[n][t[2]][t[3]][t[4]]);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值