题目
教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值。
教主最喜欢3种树,这3种树的高度分别为10,20,30。教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高。
题解
一道很有意思的dp题
模型一:
dp[i][j][k]表示前i个位置(不包括位置1),在第i个位置放j(10,20,或30),k表示上升或下降(1 or 0) 时所get的最大答案
最后和位置1的美观程度跑一遍就好啦
代码:
#include<cstdio>
#include<iostream>
#define N 100010
using namespace std;
int n,p,q,o,ans,dp[N][4][2],a[4];
int main(){
freopen("data.txt","r",stdin);
scanf("%d",&n);
scanf("%d%d%d",&p,&q,&o);
for(int i=2;i<=n;i++){
scanf("%d%d%d",&a[1],&a[2],&a[3]);
dp[i][1][1]=max(dp[i-1][2][0],dp[i-1][3][0])+a[1];
dp[i][2][0]=dp[i-1][1][1]+a[2];
dp[i][2][1]=dp[i-1][3][0]+a[2];
dp[i][3][0]=max(dp[i-1][1][1],dp[i-1][2][1])+a[3];
}
ans=max(ans,dp[n][1][1]+max(q,o));
ans=max(ans,dp[n][2][0]+p);
ans=max(ans,dp[n][2][1]+o);
ans=max(ans,dp[n][3][0]+max(p,q));
printf("%d\n",ans);
}
模型二:
dp[i][j][k]表示前i棵树已种的情况下,且第i棵树种第k种树,第i-1棵树种第j种树,的最大价值
状态转移方程详见程序内。注意由于第一棵树是有后效性的,会影响第n棵树。所以我们需要枚举第一棵树。
这里我说一下我一开始的想法
记录一个struct
struct node{
int v,p;
}f[N][4][4];
v是值,p是第一个取得位置(10或20或30)
最后再首尾比较
if(i==n){
if(k>j&&j<f[i][k][j].p)ans=max(ans,f[i][k][j].v);
if(k<j&&j>f[i][k][j].p)ans=max(ans,f[i][k][j].v);
}
发现WA了
因为当1.v==2.v时,不能确定1.p和2.p哪个更优
所以我们需要枚举第一棵树。
代码(from Vin_1999):
其中变量fir即为枚举第一棵树
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<climits>
#define rep(i,s,n) for(int (i)=(s);(i)<=(n);(i)++)
using namespace std;
const int maxn=100010;
static long long dp[maxn][4][4],fir,n,v[maxn][4];
inline void init()
{
scanf("%d",&n);
rep(i,1,n) rep(j,1,3) scanf("%d",&v[i][j]);
}
int main ()
{
freopen("e:/in.txt","r",stdin);
//freopen("e:/out.txt","w",stdout);
init();
long long ans=INT_MIN;
for(fir=1;fir<=3;fir++)
{
//printf("%d:",fir);
memset(dp,-127,sizeof(dp));
if(fir==1)
{
rep(k,2,3) dp[2][fir][k]=v[1][fir]+v[2][k];
}
else if(fir==2)
{
dp[2][fir][3]=v[1][2]+v[2][3];
dp[2][fir][1]=v[1][2]+v[2][1];
}
else
{
rep(k,1,2) dp[2][fir][k]=v[1][fir]+v[2][k];
}
rep(i,3,n) rep(j,1,3) rep(k,1,3)
{
if(j<k)
{
for(int p=j+1;p<=3;p++)
dp[i][j][k]=max(dp[i][j][k],dp[i-1][p][j]+v[i][k]);
}
else if(j>k)
{
for(int p=j-1;p;p--)
dp[i][j][k]=max(dp[i][j][k],dp[i-1][p][j]+v[i][k]);
}
}
/*rep(i,1,n) rep(j,1,3)
{
rep(k,1,2) printf("%d ",dp[i][j][k]);
printf("%d\n",dp[i][j][3]);
}*/
if(fir==1)
{
ans=max(ans,max(dp[n][1][2],max(dp[n][1][3],dp[n][2][3])));
}
else if(fir==2)
{
rep(p,2,3) ans=max(ans,dp[n][p][1]);
rep(p,1,2) ans=max(ans,dp[n][p][3]);
}
else
{
ans=max(ans,max(dp[n][3][2],max(dp[n][2][1],dp[n][3][1])));
}
}
printf("%lld",ans);
return 0;
}//by llyz-ljy
造数据
#include<cstdio>
#include<iostream>
#include<ctime>
#include<cstdlib>
#define MOD 5
using namespace std;
int n;
int main(){
freopen("data.txt","w",stdout);
srand((unsigned)time(NULL));
while((n=rand()%MOD)%2==1);
printf("%d\n",n);
for(int i=1;i<=n;i++)printf("%d %d %d\n",rand()%MOD,rand()%MOD,rand()%MOD);
}

3万+

被折叠的 条评论
为什么被折叠?



