生成一个序列的前p小的不递减排列,排列间比较大小的方式为串的长度和串在原来顺序中的序号
先写了一种最简单的不考虑剪枝且不考虑个数,生成所有排列的算法,且这个不考虑序列的递增问题,且本题目考虑的是组合问题,下面的算法是生成排列用的。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
using namespace std;
int a[1005];
bool vis[1005];
int n,p;
void dfs(int cnt,int len,vector<int> &res){
if(cnt==len){
for(int i=0;i<res.size();i++)
printf("%d ",res[i]);
printf("\n");
return;
}
for(int i=0;i<n;i++){
if(!vis[i]){
vis[i] = true;
res.push_back(a[i]);
dfs(cnt+1,len,res);
res.pop_back();
vis[i] = false;
}
}
}
int main(){
while(scanf("%d%d",&n,&p)!=EOF){
for(int i=0;i<n;i++)
scanf("%d",a+i);
memset(vis,0,sizeof(vis));
vector<int> res;
for(int len=1;len<=n;len++){
dfs(0,len,res);
}
}
return 0;
}
下面考虑剪枝以及记数问题:
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,p,a[1005];
int cnt = 0,len;
bool flag;
struct node{
int num,pos;
}res[1005];
bool judge(int beg,int end){
for(int i=beg;i<end;i++)
if(a[i]==a[end]) return false;
return true;
}
//实质上是组合问题
void dfs(int l,int pos){ //l已经生成的长度 , pos是从这一位开始考虑
if(cnt >= p)return ; //已经达到了最大要求的个数,不需要继续生成
if(l==len){ //达到了要求的个数
cnt++; //生成的个数+1
flag = true; //在当前长度下找到了一个解
for(int i=0;i<l-1;i++)
printf("%d ",res[i].num);
printf("%d\n",res[l-1].num); //输出对应的结果
return;
}
for(int i=pos;i<n;i++){ //从当前位开始向下生成
if((l!=0 && res[l-1].num<=a[i]) || l==0){ //该条件表示序列需要递增,基本要求
if(l!=0 && !judge(res[l-1].pos+1,i)) continue;
if(l==0 && !judge(0,i)) continue;
res[l].num = a[i];
res[l].pos = i;
dfs(l+1,i+1);
}
}
}
int main(){
while(scanf("%d%d",&n,&p)!=EOF){
for(int i=0;i<n;i++)
scanf("%d",a+i);
cnt = 0;
for(int i=1;i<n;i++){
flag = false;
len = i; //子串的长度
dfs(0,0);
if(cnt>=p || !flag) break;
}
printf("\n");
}
return 0;
}