HDU-2610 && HDU-2610 (dfs)

Sequence one

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

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.


题意很简单就是在给定的序列中找到固定个数的递增的子序列,如果子序列的总个数少于要求的个数,那么就把所有的子序列输出即可,注意每组测试用例就为有一空行。

技巧一:重判,这里有两个重判,第一个重判是判断如果搜索的是子序列的第一个元素,那么判断从原始序列开始到当前位置是否已经出现过该元素,若出现过则之前肯定搜索过该元素,则放弃该元素的搜索。第二个重判,当搜索的不是子序列的第一个元素时,则判断子序列的前一个元素对应原始序列的位置,然后从该位置下一个元素开始到到当前搜索的位置之前判断该元素是否出现过,如果出现过,说明该子串出现过重复的,则放弃该元素。这里的两个重判需要好好地想想,很巧妙。
技巧二:剪枝,这里的一个剪枝技巧是做了一个标记位,假如我在搜索长度为3的子串时,发现没有一个符合的,那么就不可能存在长度为4的子串符合条件。如果没有这个剪枝就会超时,看来影响很大的

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#define N 1010
const int mm = 1000000007;
using namespace std;
int n, p;
int a[N], cnt, len, path[N];
bool flag;
bool ok(int s, int e)
{
    for (int i = s; i < e; i++)
        if (a[i] == a[e])    return false;
    return true;
}
void dfs(int deep, int pos)
{
    int i;
    if (cnt >= p)    return ;
    if (deep == len)
    {
        flag = true;
        cnt++;
        for (i = 0; i < len-1; i++)
            cout << a[path[i]] << ' ';
        cout << a[path[i]] << endl;
        return ;
    }
    for (i = pos; i < n; i++)
    {
        if (!deep || (deep && a[path[deep-1]] <= a[i]))
        {
            if (!deep && !ok(0, i))    continue ;
            if (deep && !ok(path[deep-1]+1, i))    continue;
            path[deep] = i;
            dfs(deep+1, i+1);
        }
    }
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i, j;
    while(cin >> n >> p)
    {
        for (i = 0; i < n; i++)
            cin >> a[i];
        cnt = 0;
        for (i = 1; i <= n; i++)
        {
            flag = false;
            len = i;
            dfs(0, 0);
            if (cnt >= p || !flag)    break;
        }
        cout << endl;
    }

    return 0;
}

Sequence two

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 (<=100) 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 subsequence by lexicographical. For example initial sequence 1 3 2 the total legal subsequences is 5. According to order is {1}; {2}; {3}; {1,2}; {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

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
2
3
1 2
1 3

1
2
3
1 2
1 3

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

Hint

Hint : You must make sure each subsequence in the subsequences is unique.


和前一题sequence one 属于一类题,都是dfs,首先排一次序,然后再检查时注意输入时的下标,生成的子串不能够出现下标非递增的,也就是首先子串时递增的,其次下标也是递增的,然后不能有重复的子串出现。

技巧:判重的技巧,这里我们可以一开始设置一个flag=false,第一次的时候该flag的为true,然后用一个pre保留当前位置的数,然后后面在搜相同len的序列时,如果当前的数与pre是一样的,说明先前已经搜过了,直接continue就行了,否则,pre就保留这个数,然后搜len+1的数。

#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <vector>
#include <set>
#include <algorithm>
#define N 110
const int mm = 1000000007;
using namespace std;
struct aaa
{
    int num, pos; 
    friend bool operator < (const aaa x, const aaa y)
    {
        if (x.num == y.num)     return x.pos < y.pos;
        return x.num < y.num;
    }
}a[N];
int n, p;
int cnt, len, path[N];
bool dfs(int deep, int pos, int repos)
{
    int i;
    if (deep == len)
    {
        cnt++;
        for (i = 0; i < len-1; i++)
            cout << path[i] << ' ';
        cout << path[i] << endl;
        if (cnt == p)return true;
        return false;
    }
    int pre;
    bool flag = false;
    for (i = pos; i <= n; i++)
    {
        if (a[i].pos > repos)
        {
            if (!flag)
            {
                flag = true;
                pre = a[i].num;
            }
            else if (pre == a[i].num)   continue;
            pre = a[i].num;
            path[deep] = a[i].num;
            if (dfs(deep+1, i+1, a[i].pos)) return true;
        }
    }
    return false;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("1.txt", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0);
    int i, j;
    while(cin >> n >> p)
    {
        for (i = 1; i <= n; i++)
        {
            cin >> a[i].num;
            a[i].pos = i;
        }
        sort(a+1, 1+a+n);
        cnt = 0;
        for (i = 1; i < n; i++)
        {
            len = i;
            if (dfs(0, 1, 0))   break;
        }
        cout << endl;
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值