P1541 乌龟棋 线性DP
题目简介
https://www.luogu.com.cn/problem/P1541
思路
首先可以想到暴力做法:
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 是多少,这样时空间都是
状态转移方程就这样表示:
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;
}
总结
先对第一个或最后一个阶段分类讨论,找到最初的思路,然后想办法优化。
这道题的优化方式:去除一层可以被其它状态表示的状态。