Sequence one(深搜)

来源:互联网 发布:柯一正原画网络班教程 编辑:程序博客网 时间:2024/05/29 17:29

Problem Description
Search is important in the acm algorithm. When you want to solve a problem by using the search method, try to cut is very important.
Now give you a number sequence, include n (<=1000) integers, each integer not bigger than 2^31, you want to find the first P subsequences that is not decrease (if total subsequence W is smaller than P, than just give the first W subsequences). The order of subsequences is that: first order the length of the subsequence. Second order the sequence of each integer’s position in the initial sequence. For example initial sequence 1 3 2 the total legal subsequences is 5. According to order is {1}; {3}; {2}; {1,3}; {1,2}. {1,3} is first than {1,2} because the sequence of each integer’s position in the initial sequence are {1,2} and {1,3}. {1,2} is smaller than {1,3}. If you also can not understand , please see the sample carefully.
 

 

Input
The input contains multiple test cases.
Each test case include, first two integers n, P. (1<n<=1000, 1<p<=10000).
 

 

Output
For each test case output the sequences according to the problem description. And at the end of each case follow a empty line.
 

 

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
Hint
Hint : You must make sure each subsequence in the subsequences is unique.

分析:

(1)题意很简单就是在给定的序列中找到固定个数的递增的子序列,如果子序列的总个数少于要求的个数,那么就把所有的子序列输出即可,注意每组测试用例就为有一空行。
(2)技巧一:重判,这里有两个重判,第一个重判是判断如果搜索的是子序列的第一个元素,那么判断从原始序列开始到当前位置是否已经出现过该元素,若出现过则之前肯定搜索过该元素,则放弃该元素的搜索。第二个重判,当搜索的不是子序列的第一个元素时,则判断子序列的前一个元素对应原始序列的位置,然后从该位置下一个元素开始到到当前搜索的位置之前判断该元素是否出现过,如果出现过,说明该子串出现过重复的,则放弃该元素。这里的两个重判需要好好地想想,很巧妙。
(3)技巧二:剪枝,这里的一个剪枝技巧是做了一个标记位,假如我在搜索长度为3的子串时,发现没有一个符合的,那么就不可能存在长度为4的子串符合条件。如果没有这个剪枝就会超时,看来影响很大的。。。。。

代码:

#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;        }        cout<<endl;    }    return 0;}

转自:http://www.cnblogs.com/newpanderking/archive/2012/10/11/2719941.html
原创粉丝点击