NOIp 2013 to improve the group gardener

Sure enough, when the DP is not directly determine special conditions, when the data size to a certain extent, must be timed out

看了lei(机房某大佬)的代码,if(dp[i][0]!=1&&dp[i][1]!=1) break; 依然不知是何居心,猜测可能是满足m>1不能同时满足那个条件吧.想不出

接着进一步分析:

受到以前有个题求序列连续和的启发,我们可以这样设计状态:

令f[i][0]表示前i株花中的最后一株(不一定是i)满足条件A时的最多剩下的株数,

f[i][1]表示前i株花作为序列终点且最后一株(不一定是i)满足条件B时的最多剩下的株数,可以得到:

h[i]>h[i-1]时,

f[i][0]=max{f[i-1][0],f[i-1][1]+1}, f[i][1]=f[i-1][1];

h[i]==h[i-1]时,

f[i][0]=f[i-1][0],f[i][1]=f[i-1][1];

h[i]<h[i-1]时,

f[i][0]=f[i-1][0],f[i][1]=max{f[i-1][1],f[i-1][0]+1}.

答案ans=max{f[n][0],f[n][1]};

边界为f[1][0]=f[1][1]=1。

这样算法的时间复杂度可以降到O(n),很快就可以通过。

合理设计状态能够更好地发挥动态规划的优势

On the code:

#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 100010;
int h[maxn], n;
int f[maxn][2];
void init()
{
    scanf("%d", &n);
    for(int i = 1; i <= n; ++i) scanf("%d", &h[i]);
}
void work()
{
    f[1][0] = f[1][1] = 1;     //初始化
    for(int i=2; i <=n; ++i)   //依次递推分析,波动DP,看第i株花怎么放进波动序列
    {
        if(h[i-1] < h[i])      //最后一个比上一个大的情况时,更新条件A,判断条件B的f[i-1][1]+1
        {
            f[i][0] = max(f[i-1][0], f[i-1][1] + 1);
            f[i][1] = f[i-1][1];
        }
        else if(h[i-1] > h[i]) //最后一个比上一个小的情况时,,更新条件B,判断条件A的f[i-1][0]+1
        {
            f[i][1] = max(f[i-1][1], f[i-1][0] + 1);
            f[i][0] = f[i-1][0];
        }
        else                   //h[i-1]==h[i],相等的情况下,无任何处理
        {
            f[i][1] = f[i-1][1];
            f[i][0] = f[i-1][0];
        }
    }
    printf("%d", max(f[n][0], f[n][1]));
}
int main()
{
    init();
    work();
    return 0;
}

In the method previously used dynamic programming and optimization process after the DP to solve the problem.

Looking back, in fact, the problem may be simpler, but also more simple and clear thinking.

The question then is converted to: how to get to one of the longest sequence of the zigzag fluctuations?

Observation 543,212 may in fact be converted to 512, or 212 and the like, i.e., 543 points in a plurality of two continuously decreasing one point may be used alternatively,

Wherein 1 is a turning point, (in fact, in order to achieve a zigzag sequence fluctuation effect, a plurality of discrete points can be used a alternative dot)

Then the above problems can be transformed into a "turning point to find the number to meet the conditions."

code show as below:

#include<iostream>
#include<cstdio>
int high[100005];    //存储花的高度
int main()
{
    int n,ans=1,i;   //ans保存最长的序列,因为第一个位置的花,不过锯齿形状如何,始终能留下来,初始值为1
    scanf("%d",&n);
    for(int i=1;i<=n;i++)   scanf("%d",high+i);
    int flag=-1;    //flag表示满足条件的标识,flag=1表示满足条件A了,flag=0表示满足条件B
    for(int i=2;i<=n;i++)
    {
        if(high[i]>high[i-1]&&flag!=1)  //由于要得到锯齿形的队形,因此当前位置与前一个位置的高度关系应该是
        {//满足条件A时,序列长度++      //条件A和B交替满足,如果连续满足条件A,或者连续满足条件B都不应该做任何计数(缩点)
            ans++;                      //条件交替满足的意思是比如 P Q S 是一个合法序列,那么 P与 Q满足A,S与P必须满足B
            flag=1;
        }
        if(high[i]<high[i-1]&&flag!=0)
        {//满足条件B时,序列长度++
            ans++;
            flag=0;
        }
    }
    printf("%d\n",ans);
    return 0;
}

Guess you like

Origin www.cnblogs.com/zi-nai-boboyang/p/11465248.html
Recommended