搜索—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;
}

浙公网安备 33010602011771号