这题也是搜了解题报告才知道思路的,从此以后又多了项新技能了。。。。知道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 <iostream>
#include <string.h>
#include <queue>
#include <string>
#include<memory>
#include<math.h>
#include<map>
#include <vector>
#include<algorithm>
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;
}