搜索—sequence one

直达原题

Description

给你一个数字序列,包括 n (<=1000) 个整数,每个整数不大于 2^31,你希望找到前 P 个非递减的子序列(如果满足条件的子序列总数小于 P,那么就给出所有满足条件的子序列)。子序列的排序方式如下:首先按子序列的长度排序,其次按每个整数在初始序列中的位置排序。例如,初始序列为 1 3 2,满足条件的子序列共有 5 个。按顺序是:{1};{3};{2};{1,3};{1,2}。{1,3} 排在 {1,2} 前面,因为每个整数在初始序列中的位置分别为 {1,2} 和 {1,3},而 {1,2} 比 {1,3} 小。

Input

输入包含多个测试用例。
每个测试用例包括,首先是两个整数 n 和 P(其中 1 < n <= 1000,1 < p <= 10000)。

Output

对于每个测试用例,按照问题描述输出序列。每个测试用例结束后,跟随一个空行。

Sample Input

3 5
1 3 2
3 6
1 3 2
4 100
1 2 3 2

Sample Output

1
3
2
1 3
1 2

1
3
2
1 3
1 2

1
2
3
1 2
1 3
2 3
2 2
1 2 3
1 2 2

More Info

你必须确保子序列中的每个子序列都是唯一的。

分析

去重:当a作为首元素,生成了不递减子序列以后,如果后面再遇到就不用生成了。
剪枝:如果短的子序列不ok那么长的就不用考虑了

代码实现

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;

//len:搜索的长度,count:记录有多少个串了
int n,p,len,count_num;
int num[1001];

//做一个标记,如果一个短的串都不能够找到,
//那么就长的串就更不可能找到了,这里的一个巧妙地剪枝如果没用就会超时
bool flag;

typedef struct
{
    int n,pos;
}Tem;

Tem tem[1001];

//若在产生序列的前一个数字到当前这个数字中,
//出现等于num[e]的,那么说明之前已经有序列选择了num[e],
bool check(int s,int e)
{
    for(int i = s+1; i < e; i++)
    if(num[i]==num[e])return false;
    return true;
}


void print_sequence(int length)
{
    for(int i = 0; i < length-1;i++)
    cout<<tem[i].n<<" ";
    cout<<tem[length-1].n<<endl;
}

//dep:搜索的深度,也就是目前搜索到子串的长度
//pos: 当前搜索的位置
void dfs(int dep,int pos)
{
    if(count_num >= p)return;
    //搜索到了
    if(dep==len)
    {
        count_num++;
        flag = true;
        print_sequence(len);
        //已经搜索到符合的字串了
        return;
    }
    for(int i=pos;i<n;i++)
    {
        if((dep!=0&&tem[dep-1].n<=num[i])||dep==0)
        {
            if(dep==0&&!check(-1,i))//检查是否该数当过序列段的首位
            continue;
            if(dep!=0&&!check(tem[dep-1].pos,i))//也是一种判重剪枝,如果在序列段中间位置该数出现过,那就不能再次出现了
            continue;
            tem[dep].n = num[i];
            tem[dep].pos = i;
            dfs(dep+1,i+1);
        }
    }
    return;
}

int main()
{
    while(cin>>n>>p)
    {
        for(int i=0;i<n;i++)
        cin>>num[i];
        count_num = 0;
        for(int i = 1;i < n;i++)
        {
            flag=false;
            len = i;
            dfs(0,0);
            if(count_num>=p||!flag)break;//这里flag是如果短的序列段都找不到就没必要找长的序列段了(长的是在短的上再添加出来的)就可以直接跳出循环
        }
        cout<<endl;
    }
    return 0;
}
posted @ 2023-08-22 02:01  LongDz  阅读(19)  评论(0)    收藏  举报