洛谷P1133 教主的花园

题目描述

教主有着一个环形的花园,他想在花园周围均匀地种上n棵树,但是教主花园的土壤很特别,每个位置适合种的树都不一样,一些树可能会因为不适合这个位置的土壤而损失观赏价值。

教主最喜欢3种树,这3种树的高度分别为10,20,30。教主希望这一圈树种得有层次感,所以任何一个位置的树要比它相邻的两棵树的高度都高或者都低,并且在此条件下,教主想要你设计出一套方案,使得观赏价值之和最高。

输入输出格式

输入格式:

输入文件garden.in的第1行为一个正整数n,表示需要种的树的棵树。

接下来n行,每行3个不超过10000的正整数ai,bi,ci,按顺时针顺序表示了第i个位置种高度为10,20,30的树能获得的观赏价值。

第i个位置的树与第i+1个位置的树相邻,特别地,第1个位置的树与第n个位置的树相邻。

输出格式:

输出文件garden.out仅包括一个正整数,为最大的观赏价值和。

输入输出样例

输入样例#1:
4 
1 3 2 
3 1 2 
3 1 2 
3 1 2
输出样例#1:
11

说明

【样例说明】

第1~n个位置分别种上高度为20,10,30,10的树,价值最高。

【数据规模与约定】

对于20%的数据,有n≤10;

对于40%的数据,有n≤100;

对于60%的数据,有n≤1000;

对于100%的数据,有4≤n≤100000,并保证n一定为偶数。

一眼看上去是DP问题。然而1和n位置会相互影响,导致决策有后效性。

枚举1位置所种的树(只有三种情况),分别DP,再从三种情况的解中取最大值。

设f[位置][该位置种的树][前一位置种的树]=最大收益

决策方法很多,我选择暴力枚举每个决策。具体看代码

 1 /*by SilverN*/
 2 #include<algorithm>
 3 #include<iostream>
 4 #include<cstring>
 5 #include<cstdio>
 6 #include<cmath>
 7 #include<vector>
 8 using namespace std;
 9 const int mxn=100010;
10 int read(){
11     int x=0,f=1;char ch=getchar();
12     while(ch<'0' || ch>'9'){if(ch=='-')f=-1;ch=getchar();}
13     while(ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}
14     return x*f;
15 }
16 int n;
17 int f[mxn][3][3];//长度,末尾两种树 
18 int a[3][mxn];
19 int ans=0;
20 void DP(int first){//枚举第一棵树 
21     memset(f,0,sizeof f);
22     int i,j;
23     for(i=0;i<3;i++){
24         if(i==first)continue;
25         f[2][i][first]=a[i][2]+a[first][1];
26     }
27     for(i=3;i<=n;i++){//枚举位置 
28         for(j=0;j<3;j++){//枚举上一位置树的种类 
29             if(j==0){//中间是最低的树,两边都需要更高 
30                 for(int k=1;k<=2;k++)
31                     f[i][k][0]=max(f[i-1][0][1],f[i-1][0][2])+a[k][i];
32                 continue;
33             }
34             if(j==2){//中间是最高的树,两边都需要更低 
35                 for(int k=0;k<=1;k++)
36                     f[i][k][2]=max(f[i-1][2][0],f[i-1][2][1])+a[k][i];
37                 continue;
38             }
39             if(j==1){//中间是中等的树,两边要么都高要么都低 
40                 f[i][2][1]=f[i-1][1][2]+a[2][i];
41                 f[i][0][1]=f[i-1][1][0]+a[0][i];
42             }
43         }
44     }
45     //
46     switch(first){//根据第1棵树的种类决策第n棵树的种类 
47         case 0:{
48             int tmp=0;
49             for(int k=1;k<=2;k++){
50                 for(int l=0;l<k;l++)
51                     tmp=max(f[n][k][l],tmp);
52             }
53             ans=max(ans,tmp);
54             break;
55         }
56         case 1:{
57             int tmp=0;
58             tmp=max(f[n][2][1],f[n][2][0]);
59             tmp=max(tmp,max(f[n][0][1],f[n][0][2]));
60             ans=max(ans,tmp);
61             break;
62         }
63         case 2:{
64             int tmp=0;
65             for(int k=0;k<=1;k++){
66                 for(int l=k+1;l<=2;l++)
67                     tmp=max(f[n][k][l],tmp);
68             }
69             ans=max(tmp,ans);
70             break;
71         }
72     }
73     
74 }
75 int main(){
76     n=read();
77     int i,j;
78     for(i=1;i<=n;i++){
79         a[0][i]=read();a[1][i]=read();a[2][i]=read();
80     }
81     for(i=0;i<3;i++)DP(i);
82     printf("%d
",ans);
83     return 0;
84 }
原文地址:https://www.cnblogs.com/SilverNebula/p/6024169.html