1. 程式人生 > >CH1101 火車進棧(爆搜)||(列舉+判斷)

CH1101 火車進棧(爆搜)||(列舉+判斷)

題意

有n個元素,編號1~n,它們依次進棧,隨時可以出棧。請你按《字典序》輸出前20種可能的出棧方案。

題解1

爆搜
對於一個數k要進棧,先讓棧內的元素考慮出棧,然後再入棧。當出棧數等於n時,輸出。

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=30;

int n;
int top=0,sta[maxn];
int on=0,out[maxn];
int cnt=0;

void dfs(int k)
{
    if(on==n)//出棧數等於n時,輸出 
    {
        cnt++;
        for(int i=1;i<=n;i++) printf("%d",out[i]);
        printf("\n");
        if(cnt==20) exit(0);
        return ;
    }
    
    if(top>0)//先讓棧內的元素考慮出棧
    {
        int tp=sta[top--];
        out[++on]=tp; 
        dfs(k);
        sta[++top]=tp;
        on--;
    }
    
    if(k<=n)//然後再入棧
    {
        sta[++top]=k;
        dfs(k+1);
        top--;
    }
}

int main()
{
    scanf("%d",&n);
    dfs(1);
    return 0;
}

題解2

列舉+判斷
判斷原理:一個序列能是出棧序列,當且僅當較大值出站後,後續的小值依次出棧
全排列列舉即可。

程式碼

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=30;

int n;
int a[maxn];
bool v[maxn];
int cnt=0;

bool check()//判斷是否是出棧序列
{
    for(int i=1;i<=n;i++)
    {
        int can_mx=a[i];
        for(int j=i+1;j<=n;j++)
            if(a[j]<a[i])
                if(a[j]>can_mx) return false;
                else can_mx=a[j];
    }
    return true;
}

void dfs(int k)//全排列 
{
    if(k==n+1)
    {
        if(check())
        {
            cnt++;
            for(int i=1;i<=n;i++) printf("%d",a[i]);
            printf("\n");
            if(cnt==20) exit(0);
        }
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        if(!v[i])
        {
            v[i]=true;
            a[k]=i;
            dfs(k+1);
            v[i]=false;
        }
    }
}

int main()
{
    scanf("%d",&n);
    dfs(1);
    return 0;
}