HDU [ Sequence second ]——dfs+判重+剪枝

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.<br>Now give you a number sequence, include n (&lt;=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. <br>
 

Input
The input contains multiple test cases.<br>Each test case include, first two integers n, P. (1<n<=100, 1<p<=100000). <br>
 

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 51 3 23 61 3 24 1001 2 3 2
 

Sample Output
 
  
1231 21 31231 21 31231 21 32 22 31 2 21 2 3
 

==========================

        这道题目和上一道题目的不同在于:对于同长度的子集,我们要按照字典排序输出;其次我们输出的解中不应该包含原集合(即使它是合法的)。

        按照字典顺序输出,我们首先想到的肯定是对原数列排序,但这样会破坏数列的原始顺序,而我们所寻找的解是与数列的初始序号有关的,所以我们用结构体来记录数据的初始编号;另外,在判重时我们也不能单单关注当前数据是否在之前出现过了,因为之前出现的数据可能因为初始编号没较小有被用过(判重的实质:放入当前数据所构成的解集合是否在之前出现过),所以我们只需要在上一题的基础上稍作修改即可,(①加入结构体记录初始编号;②修改判重函数)。

AC代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,t,sum;
int length;
bool flag;
int position[10010];
struct fc
{
	int index,num;
}a[10010];
bool complare(fc x,fc y)
{
	if(x.num==y.num)return x.index<y.index;
	return x.num<y.num;
}
bool same(int x,int y)
{
	for(int i=x+1;i<=y-1;++i)
	{
		if(a[y].num==a[i].num&&a[i].index>a[x].index)return 0;//与当前数相等的数据并不一定在之前构成过可行解;
	}
	return 1;
}
void search(int x,int start)
{
	if(sum>=t)
	{
		return ;
	}
	if(x>length)
	{
		flag=1;
		sum++;
		cout<<a[position[1]].num;
		for(int i=2;i<=length;++i)
		       cout<<" "<<a[position[i]].num;//HDU注意输出格式;
		cout<<endl;
		return ;
	}
	for(int i=start;i<=n;++i)
	{
		if((x==1&&same(position[x-1],i)==1)||(x!=1&&a[i].num>=a[position[x-1]].num&&same(position[x-1],i)==1&&a[i].index>a[position[x-1]].index))//是否满足初始编号;
		{
			position[x]=i;
			search(x+1,i+1);
		}
	}
}
int main()
{
	while(cin>>n>>t)
	{
		sum=0;
		memset(a,0,sizeof(a));
		memset(position,0,sizeof(position));
		for(int i=1;i<=n;++i)
		               cin>>a[i].num,a[i].index=i;
		sort(a+1,a+1+n,complare);//排序在两数相同时,初始编号小的数优先级高;
		for(int i=1;i<n;++i)
		{
			length=i;
			flag=0;
			search(1,1);
		        if(!flag||sum>=t)
			{

				break;
			}


		}
		cout<<endl;
	}
	return 0;
}

The end;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值