组合的字典序
时间限制(普通/Java):1000MS/3000MS 运行内存限制:65536KByte
总提交:51 测试通过:28
总提交:51 测试通过:28
描述
一个组合问题可以抽象为从n-1个整数0、1、2 ... (n-1)中选取m个。选中的m个数构成序列,并且从小到大排列,称为生成序列。不同的生成序列按照字典序有先后顺序。一个生成序列的直接后继是另外一个生成序列:这个序列与其直接后继之间没有其他任何生成序列。最后一个生成序列之后的生成序列不存在,但可以人为地规定为每个元素的值都是-1。
输入
第一行是一个整数k,表示测试用例的多少。每个测试用例的输入是若干独立的行。
对每一个测试用例,其第一行是两个整数ni和mi(用单个空格隔开),第一个整数ni(ni在区间[2,30]中),表示了被选序列的大小;第二个整数mi(mi在区间[1, ni]中),表示被选出序列的大小。后面的mi行表示被选出的序列,每一行分别是一个正整数,在[0, ni-1]之中,并且递增排列。
输出
对每一个mi长度的输入序列,用mi行输出其直接后继(长度仍然是mi)。
样例输入
3
10 4
0
2
8
9
3 2
1
2
5 2
2
4
样例输出
0
3
4
5
-1
-1
3
4
·第二遍打这个题了,,比第一遍相对来说顺手的多
分情况讨论并作处理,迭代开发,对于这类模拟题,感觉真的屡试不爽。。。
#include <iostream>
#include <algorithm>
#include <string.h>
#include <math.h>
#include <stdio.h>
#include <queue>
#include <stack>
using namespace std;
#define N 10100
#define INF 1<<27
#define LL long long
//先已经没有后继的; 有,则计算
int f[N];
int check(int n,int m){
int flag=1;n--;
for(int i=m-1;i>=0;i--){
if(f[i]==n){
n--;
}else{
flag=0;break;
}
}
return flag;
}
void deal(int n,int m){
int flag=0;
for(int i=0;i<m;i++)
if(f[i]==(n-1)){
flag=i;break; //含最大的数字! 处理比较麻烦
}
if(!flag){
//简单+1处理
for(int i=0;i<m-1;i++)
printf("%d\n",f[i]);
printf("%d\n",f[m-1]+1);
}else{
n-=2;int i;
for(i=flag-1;i>=0;i--){
if(f[i]==n){
n--;continue;
}else{
flag=i;break;
}
}
if(i==-1){
//没有后继
for(int i=0;i<m;i++)
printf("-1\n");
}
else{
//有后继
for(int i=0;i<flag;i++){
printf("%d\n",f[i]);
}
int t = f[flag]+1;
for(int i=flag;i<m;i++){
printf("%d\n",t);t++;
}
}
}
}
int main(){
int t;scanf("%d",&t);
while(t--){
int n,m;
scanf("%d %d",&n,&m);
for(int i=0;i<m;i++)
scanf("%d",&f[i]);
if(check(n,m)){
for(int i=0;i<m;i++)
printf("-1\n");
continue;
}
//否则,计算直接后继并输出
deal(n,m);
}
return 0;
}