算法竞赛刷题笔记ii

进出栈序列问题

1–N N个整数和一个无限大的栈 每个数要进出栈一次,进栈顺序为1,2,…,N,可能出栈的顺序有多少种
这个题求的就是一个catalan数 ( 2 n n ) 1 n + 1 \binom{2n}{n}\frac{1}{n+1} (n2n)n+11
有两种dp方法 一种一维dp 数组的S,S[N]表示进栈顺序为1,2,3,…,N时可能的出栈序列总数。
S[N]= ∑ K = 1 N S k − 1 ∗ S N − K \sum_{K=1}^NS_{k-1}*S_{N-K} K=1NSk1SNK

	int n;
    while(cin>>n){
        vector<int> S(n+1);
        S[0] = 1;
        for(int i=1;i<=n;i++)
            for(int k=1;k<=i;k++)
                S[i] += S[k-1]*S[i-k];
        cout<<S[n]<<endl;
    }

时间复杂度为 O ( n 2 ) O(n^2) O(n2)

另一种dp是用二维数组 dp[i][j] 表示有i个数尚未进栈,目前有j个数在栈里,已经有n-i-j个数出栈的方法总数 dp[0][i] = 1 (i=0,1,2,3…,n) 因为只能不停的出栈 所以方法数只能为1 要求的目标是dp[n][0]
处于(i,j)状态的dp 要么进栈 要么出栈 即会分离成两种dp状态
dp[i][j] = dp[i-1][j+1] + dp[i][j-1] 前面是进栈 后面是出栈
数据限制: 首先元素总数为n 还没进栈和已经出栈的总数不可能超过n 即 i + j < = n i+j<=n i+j<=n
j = 0 j=0 j=0时 栈为空 不能进行出栈操作 所以j为0是 dp[i][j] = dp[i-1][j+1]

	int n=0;
    while(cin>>n){
        vector<vector<int> > dp(n+1,vector<int>(n+1));
        for(int i=0;i<n+1;i++)
            dp[0][i] = 1;
        for(int i=1;i<=n;i++)
            for(int j=0;j<=n-i;j++)
                dp[i][j] = dp[i-1][j+1] + (j==0 ? 0 : dp[i][j-1]);
        cout<<dp[n][0]<<endl;
    }

POJ 2559

在这里插入图片描述
这题不会做,看了一下书上的提示,先考虑矩形的高度是单调增加的,然后考虑一般情况的情况。
用的是单调栈 栈里面的元素的值严格单调递增,碰见比栈顶小的数 依次把栈的元素弹出,直到栈顶的数小于等于num,用width记录栈中每个元素的宽度,如果遇见与栈顶相等的元素 那么就把栈顶元素对应的宽度加1。弹出的时候 由于弹出的矩形高度都大于num 所以最后这些被弹出的矩形的宽度要加到num对应的宽度上去

我的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<vector>
#include<sstream>
using namespace std;

typedef long long ll;
ll st[100007];
int width[100007];

int main()
{
    while(true){
        int n,top = 0,num,w = 0;
        ll mx = 0;
        cin>>n;
        if(n == 0)
            break;
        n++;
        while(n--){
            if(n >= 1)
                scanf("%d",&num);
            else
                num = 0;//在输入序列中额外增加一个为0的输入
            if(num > st[top]){
                st[++top] = num;
                width[++w] = 1;
            }
            else{
                ll t = 0,wt = 0;
                while(top > 0 && num < st[top]){
                    wt += width[w--];
                    t = st[top--] * wt;
                    if(t > mx)
                        mx = t;
                }
                if(num == st[top])
                    width[w] += wt+1;
            }
        }
        cout<<mx<<endl;
    }
    return 0;
}

wrong answer了 发现栈弹出的时候 还有一种st[top] < < < num的情况 那么应该在栈里加入num
修改为:

if(num == st[top])
	width[w] += wt+1;
else{
    st[++top] = num;
     width[++w] = wt+1;
}

改完以后AC了 500K 141ms

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值