1024 Sequence one
题意:对于给定序列,找到指定个数子序列,如果全部子序列少于给定个数,输出全部的子序列。子序列元素按递增顺序,输出按子序列长度及位置。
思路:根据子串长度搜索,保存上一次选择的数和所选的数的下标,当选择下一个数的时候和上次所选择的数比较大小,大于等于的符合条件,符合条件的输出。
对于每一个元素,如果是子序列的第一个元素,那么判断在原序列中,该位置之前是否出现过该元素,若出现过则放弃该元素。如果不是子序列的第一个元素,判断子序列前一个位置在原序列中原始下标,到该元素是否出现过,如果出现则放弃。
感想:题意都一直没有明白,始终不清楚子序列的选择原则,无奈啊!找题解研究了半天,终于有了眉目。
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
int n,p,l,cnt; //搜索长度,cnt记录子串个数
int num[1001];
//做一个标记,如果一个短的串都不能够找到,
//那么就长的串就更不可能找到了,这里的一个巧妙地剪枝如果没用就会超时
bool flag;
struct Temp{
int n,pos;
};
Temp tem[1001];
//检查产生序列前一个数字到当前数字num[t]是否出现该数
bool check(int q,int t){
for(int i=q+1;i<t;i++)
if(num[i]==num[t]) return false;
return true;
}
void output(int len){
for(int i=0;i<len-1;i++)
cout<<tem[i].n<<" ";
cout<<tem[len-1].n<<endl;
}
//dep搜索的深度,即目前搜索到子串的长度
//当前搜索位置
void dfs(int dep,int pos){
if(cnt>=p) return ; //搜索到了
if(dep==l){ //已经搜索到符合题目要求的子串个数
cnt++;
flag=true;
output(l);
return ;
}
for(int i=pos;i<n;i++){
if(dep!=0&&tem[dep-1].n<=num[i]||dep==0) //tem[dep-1].n上一节点选中的数字
{
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];
cnt=0;
for(int i=1;i<n;i++){
flag=false;
l=i;
dfs(0,0);
if(cnt>=p||!flag) break; //!flag子串不合适,那么直接退出
}
cout<<endl;
}
return 0;
}