[DP动归]-POJ-1836-士兵排队(最长升序子串)

博客探讨了一道编程题POJ-1836,涉及到让士兵出列的场景,要求剩余士兵形成的身高序列构成三角形。关键点在于理解题目要求士兵序列严格单调递增或递减。博主分享了解题思路,使用动态规划(DP)方法,定义dp1和dp2分别表示从左往右和从右往左的最长升序子串,最后通过两者的组合找到最长的三角形。代码实现中,博主注意到了一个常见陷阱并进行了修正。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:点击打开链接

题目描述:- =,第一遍因为英语渣看错题意我会乱说?。。嘛,总之题意就是让几个士兵出列,剩下的士兵都可以看到左侧或者右侧的无穷远处(身高构成一个三角形的构型)。如图。


题目坑点:注意!我被坑了好几次!(泪目)。中间最高的两位是允许酱紫的,但是如果不是中间的那两个大高个,剩下的人就必须严格单调递增或递减。这里我看到的另一个博客,写的不错:(但是注意:他给的sample的输出是错的,在他博客评论里是正确的)→点击打开链接

解题思路:dp1【i】表示从左往右到这一点能构成的最长升序子串的长度,dp1【i】等于之前所有比【i】矮的人里dp1最大的加一,差不多原理再从右往左找一遍dp2,表示从右往左能构成的最长升序子串——也就是从左往右的最长降序子串。好了,(dp1【i】+dp2【i】-1)就可以表示这点能”发出去的“最长的三角形,然后就知道答案咯~

AC代码:

好吧。。别吐槽那个solve1和solve2了。就是写渣了而已嘛。然后为了避免那个坑点。。我把代码改的更加渣了

- =(泪、、)

#include <cstdio>
#include <cstring>
#include <iostream>

using namespace std;

double arr[1050],dp1[1050],dp2[1050],temp[1050];
int N;

void solve1(double dp[1050])
{
    int i,j,cc,flag;
    dp[0]=1;
    for(i=1;i<N;i++)
    {
        cc=-1;
        flag=0;
        for(j=0;j<i;j++)
        {
            if(arr[i]>arr[j])
                {temp[++cc]=dp[j];flag=1;}
        }
        if(flag)
        {
            int maximum=temp[0];
            for(j=0;j<=cc;j++)
                if(maximum<temp[j])
                    maximum=temp[j];
            dp[i]=maximum+1;
        }
        else
        {
            dp[i]=1;
        }
    }
}

void solve2(double dp[1050])
{
    int i,j,cc,flag;
    dp[N-1]=1;
    for(i=N-2;i>=0;i--)
    {
        cc=-1;
        flag=0;
        for(j=N-1;j>i;j--)
        {
            if(arr[i]>arr[j])
                {temp[++cc]=dp[j];flag=1;}
        }
        if(flag)
        {
            int maximum=temp[0];
            for(j=0;j<=cc;j++)
                if(maximum<temp[j])
                    maximum=temp[j];
            dp[i]=maximum+1;
        }
        else
        {
            dp[i]=1;
        }
    }
}

int ok(int maximum,int nimas)
{
    int i;
    for(i=nimas+1;i<N;i++)
    {
        if(dp1[i]+dp2[i]==maximum&&arr[i]==arr[nimas])
            return 1;
    }
    return 0;
}

int main()
{
    //freopen("alignment_input.txt","r",stdin);
    cin>>N;
    int i;
    for(i=0;i<N;i++)
        scanf("%lf",&arr[i]);
    solve1(dp1);
    solve2(dp2);
/*
    for(i=0;i<N;i++)
        cout<<dp1[i]<<" ";
    cout<<endl;
    for(i=0;i<N;i++)
        cout<<dp2[i]<<" ";
    cout<<endl;
*/
    int nimas=0;
    int maximum=dp1[0]+dp2[0];
    for(i=1;i<N;i++)
    {
        if(maximum<dp1[i]+dp2[i])
            {maximum=dp1[i]+dp2[i];nimas=i;}
    }
    if(ok(maximum,nimas))
        cout<<N-maximum<<endl;
    else
        cout<<N-maximum+1<<endl;
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值