bjfuOJ 1017组合的字典序(模拟求直接后继,分情况讨论)


组合的字典序

时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交: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;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值