HDU Sequence two 2611 DFS搜索判重

这题也是搜了解题报告才知道思路的,从此以后又多了项新技能了。。。。知道DFS怎么判重了


题意是在一连串数字中,找出前p个连续不下降子序列,按字典序,以数字为单位,1 ,23序列应该排在12,3序列的前面


这题最主要的难度是估计时间复杂度和判重。

时间复杂度:其实想一想,100个数字,每次扫描一遍这100个数字必定可以找出一个序列,p最大为100000,所以时间复杂度最大为o(n*p)(未优化),应该还是可以接受的。

原来想了很多优化的方法,但是最后都没有实践。。。。最后写了一个最挫的算法。。

判重:先将序列排序,按数字大小排,这样可以保证输出的序列是字典序。每个序列第一个数字之前不能有跟这个数字相同的数字,假设现在的数字在序列中的位置为pos,在dfs中,到达这个数字前经过的数字的位置为pre,  那么dfs无非就是每个数字选或者不选,如果前面有跟你相同的数字,那么你可以形成的序列,前面那个数字也可以形成,所以在pre到pos之间(不包括pre,pos)的并且在原序列中的位置大于pos[pre]  数字不能跟num[pos]相同。


#pragma warning (disable : 4786)
#include 
#include 
#include 
#include 
#include
#include
#include
#include 
#include
using namespace std;

bool tag;
int n,p,sum,deepth,ans[105];

struct node
{
	int data,pos; //pos为这个数字在初始序列中的位置,data是值
	bool operator < (node a) const
	{
		if(a.data != data)
			return data < a.data;
		return pos < a.pos;
	}
}num[105];

void dfs(int pos,int pre,int len)
{
	int i;
	if(sum == p)  //如果够P了就不搜了
		return ;

	if(pre == -1) //判重
	{
		for(i = pos - 1;i >= 0;--i)
		{
			if(num[i].data == num[pos].data)
				return ;
		}
	}
	else
	{
		for(i = pos - 1;i > pre;--i)
		{
			if(num[i].pos > num[pre].pos && num[i].data == num[pos].data)
				return ;
		}
	}

	
	ans[len] = num[pos].data;
	len++;

	if(len >= deepth)  // 满足长度就输出序列
	{
		sum++;
		tag = 1;
		for(i = 0;i < deepth - 1;++i)
			printf("%d ",ans[i]);
		printf("%d\n",ans[i]);
		return ;
	}

	for(i = pos + 1;i < n;++i)
	{
		if(num[i].pos > num[pos].pos)
			dfs(i,pos,len);		
	}
}


int main()
{
	while(scanf("%d%d",&n,&p) != EOF)
	{
		for(int i = 0;i < n;++i)
		{
			scanf("%d",&num[i].data);
			num[i].pos = i;
		}

		sort(num,num + n);
		sum = deepth = 0;
		tag = 1;
		while(sum < p && tag) //如果一次循环没有新的结果就没必要继续搜索了
		{
			deepth++;  //每次搜索出来的序列长度 
			tag = 0;
			for(i = 0;i < n;++i)
				dfs(i,-1,0);
		}
		puts("");
	}
	return 0;
}


你可能感兴趣的:(HDU Sequence two 2611 DFS搜索判重)