P1541 乌龟棋 线性DP

posted on 2023-02-23 12:05:11 | under 题集 | source

题目简介

https://www.luogu.com.cn/problem/P1541

思路

首先可以想到暴力做法:

\(dp[i][a][b][c][d]\) 代表在第 i 个格子时, 用了 f1 张 1 , f2 张 2 , f3 张 3 , f4 张 4 时的最大分数。

然后用五重循环代表每个阶段。

别忘了初始化,$ dp[1][0][0][0][0]=a[1] $

if(i-1>=0) dp[i][f1][f2][f3][f4]=max(dp[i][f1][f2][f3][f4],dp[i-1][f1-1][f2][f3][f4]);
if(i-2>=0) dp[i][f1][f2][f3][f4]=max(dp[i][f1][f2][f3][f4],dp[i-2][f1][f2-1][f3][f4]);
if(i-3>=0) dp[i][f1][f2][f3][f4]=max(dp[i][f1][f2][f3][f4],dp[i-3][f1][f2][f3-1][f4]);
if(i-4>=0) dp[i][f1][f2][f3][f4]=max(dp[i][f1][f2][f3][f4],dp[i-4][f1][f2][f3][f4-1]);
dp[i][f1][f2][f3][f4]+=a[i];

这样做可以拿50分,时间、空间都会超。

但是我们可以发现,i 这个状态是没必要的。

因为我们可以有后四个状态推出 i 是多少,这样时空间都是 $ 40^4 $ 。

状态转移方程就这样表示:

int i=1+f1+f2*2+f3*3+f4*4; //细节加一 
if(f1>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1-1][f2][f3][f4]+a[i]);
if(f2>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1][f2-1][f3][f4]+a[i]);
if(f3>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1][f2][f3-1][f4]+a[i]);
if(f4>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1][f2][f3][f4-1]+a[i]);

结束,附上程序。

#include<bits/stdc++.h>
using namespace std;
int n,a[505],dp[45][45][45][45];
int m,f[5],b;
int main()
{
	cin>>n>>m;
	for(int i=1; i<=n;i++) cin>>a[i];
	for(int i=1; i<=m;i++)
	{
		cin>>b;
		f[b]++;
	}
	dp[0][0][0][0]=a[1];
	for(int f1=0; f1<=f[1];f1++)
	 for(int f2=0; f2<=f[2];f2++)
	  for(int f3=0; f3<=f[3];f3++)
	   for(int f4=0; f4<=f[4];f4++)
	   {
	   	int i=1+f1+f2*2+f3*3+f4*4; //细节加一 
	    	if(f1>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1-1][f2][f3][f4]+a[i]);
	    	if(f2>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1][f2-1][f3][f4]+a[i]);
	    	if(f3>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1][f2][f3-1][f4]+a[i]);
	    	if(f4>0) dp[f1][f2][f3][f4]=max(dp[f1][f2][f3][f4],dp[f1][f2][f3][f4-1]+a[i]);
	   }
	cout<<dp[f[1]][f[2]][f[3]][f[4]];
	return 0;
 } 

总结

先对第一个或最后一个阶段分类讨论,找到最初的思路,然后想办法优化。

这道题的优化方式:去除一层可以被其它状态表示的状态。

posted @ 2026-01-14 17:55  Zwi  阅读(0)  评论(0)    收藏  举报