这个题,我发现了不是所有的dfs都必须要用到vis[i]= 1 ~dfs~ vis[i]=0,这样的结构。
这个题技巧好多,膜拜了一波大神代码,按着思路摸了一遍。
主要是注意整体的解题思路以及减枝操作:
技巧一:重判,这里有两个重判,
第一个重判是判断如果搜索的是子序列的第一个元素,那么判断从原始序列开始到当前位置是否已经出现过该元素,若出现过则之前肯定搜索过该元素,则放弃该元素的搜索。第二个重判,当搜索的不是子序列的第一个元素时,则判断子序列的前一个元素对应原始序列的位置,然后从该位置下一个元素开始到到当前搜索的位置之前判断该元素是否出现过,如果出现过,说明该子串出现过重复的,则放弃该元素。这里的两个重判需要好好地想想,很巧妙。
技巧二:剪枝,这里的一个剪枝技巧是做了一个标记位,假如我在搜索长度为3的子串时,发现没有一个符合的,那么就不可能存在长度为4的子串符合条件。如果没有这个剪枝就会超时,看来影响很大的
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define MAXN 1010
struct Node{
int num,pos;
}path[MAXN];
int num[MAXN];
int n,p,_count,len;
bool flag;
bool Judge(int st,int ed){
for(int i=st;i<ed;i++){
if(num[i]==num[ed])return false;
}
return true;
}
void dfs(int l,int pos){
if(_count>=p)return ;
if(l==len){
_count++;
flag=true;
for(int i=0;i<l-1;i++){
cout << path[i].num<<" ";
}
cout << path[l-1].num<<endl;
return ;
}
for(int i=pos;i<n;i++){
if((l!=0&&path[l-1].num<=num[i])||l==0){
if(l!=0&&!Judge(path[l-1].pos+1,i))continue;
if(l==0&&!Judge(0,i))continue;
path[l].num=num[i];
path[l].pos=i;
dfs(l+1,i+1);
}
}
}
int main(){
while(cin>>n>>p){
for(int i=0;i<n;i++)
cin>>num[i];
_count=0;
for(int i=1;i<n;i++){
flag=false;
len=i;
dfs(0,0);
if(_count>=p||(!flag))break;
}
cout <<endl;
}
return 0;
}