SJT生成排列(清华OJ)

题目

给定n和k,输出用SJT算法生成的第k个排列。其中,第一个排列为1,2,3,…,n。
输入:一行两个整数n,k。
输出:一行用空格隔开的n个数,是SJT算法生成的第k个排列。
数据规模与约定:①保证存在第k个排列;②对所有数据,n<=10;③时间限制为1s,空间限制为512MB。
Sample Input: 5 23
Sample Output: 4 1 5 3 2

SJT算法

初始状态为“向量”1,2,3,…,n(统一朝左)。
①找到最大的可移动数m(只要一个数m指向比它小的数,那么数m就可以移动)。
②将m与被m指向的数交换位置。
③比m大的数方向要改变,比m小的数方向不变。
④重复上述步骤,直到找不出最大可移动数为止。

思路

单纯套用SJT模板

代码

正确代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    vector<int>a(n+1);
    for(int i=1; i<=n; i++) a[i]=i; //第一轮初始是1-n
    vector<int>d(n+1);
    for(int i=1; i<=n; i++) d[i]=-1; //方向全部朝左,每个数可以按照它的方向移动一步
    for(int r=1; r<=k-1; ++r) //第一轮已经结束,要找第k轮结果,还要进行k-1轮
    {
        int mobile_int=0;//目前最大可移动数
        int pos=0;//这个可移动数的位置
        for(int i=1; i<=n; i++)//寻找最大可移动数
        {
            int j=i+d[i];//将要走到的位置
            if(j==0||j>n||a[j]>a[i]) continue;//不能到最左边边界,也不能到最右边边界,一个数不能跨过比它大的数
            if(a[i]>mobile_int)
            {
                mobile_int=a[i];
                pos=i;
            }
        }
        int tpos=pos+d[pos];//可移动数的下一步的位置
        swap(a[pos],a[tpos]);//交换数字
        swap(d[pos],d[tpos]);//交换方向
        for(int i=1; i<=n; i++)
        {
            if(a[i]>mobile_int) d[i]=-d[i];//大于最大可移动数的数a[i]的方向d[i]要取反
        }
    }
    for(int i=1; i<n; ++i)
    {
        printf("%d ",a[i]);
    }
    printf("%d\n",a[n]);
    return 0;
}

网上模板
PS:不知道为啥要写那么复杂。。。可能是要照顾到全部数据???

//邻位对换法
void exchange(int length){
    Item * data = (Item *)malloc(sizeof(Item) * length);
    int index, indexOfMax;
    for (index = 0; index < length; ++index){
        data[index].digit = index + 1;//初始化
        data[index].direction = -1;//定义初始方向(全部向左)
        data[index].mobile = (index != 0) ? 1 : 0;
    }
    indexOfMax = length - 1;
    FILE * fp = fopen("exchange.txt", "w");
    exPrint(data, length, fp);
    while (1== data[indexOfMax].mobile || existMobile(data, length)){
        if (1== data[indexOfMax].mobile){
            int direction = data[indexOfMax].direction;
            exSwap(data, indexOfMax, indexOfMax+direction);
            indexOfMax += direction;
            if ((indexOfMax == 0 && direction == -1) || (indexOfMax == length-1 && direction == 1)){
                toMobileorNot(data, length);
            }
        } 
        else{
            index = findMax(data, length);
            if (index == -1)
                break;
            int direction = data[index].direction;
            exSwap(data, index, index + direction);
            index += direction;
            changeDirection(data, length, index);
            toMobileorNot(data, length);
        }
        exPrint(data, length, fp);
    }
    fclose(fp);
    free(data);
}
int existMobile(Item data[], int length){//判断是否存在可移动数
    int index;
    for (index = 0; index < length; ++index){
        if (data[index].mobile == 1)
            return 1;
    }
    return 0;
}
int findMax(Item data[], int length){//找到最大的可移动数
    int ans = -1;
    for (int index = 0; index < length; ++index){
        if (data[index].mobile == 1){
            if (ans == -1)
                ans = index;
            else if (data[index].digit > data[ans].digit)
                ans = index;
        }
    }
    return ans;
} 
void changeDirection(Item data[], int length, int index){//改变大于可移动数的数的方向
    for (int i = 0; i < length; ++i){
        if (data[i].digit > data[index].digit){
            data[i].direction = -data[i].direction;
        }
    }
} 
void toMobileorNot(Item data[], int length){
    if (data[0].direction == 1 && data[0].digit > data[1].digit)
        data[0].mobile = 1;
    else
        data[0].mobile = 0;
    for (int i = 1; i < (length - 1); ++i){
        int direction = data[i].direction;
        if (data[i].digit > data[i+direction].digit)
            data[i].mobile = 1;
        else
            data[i].mobile = 0;
    } 
    if (data[length-1].direction == -1 && data[length-1].digit > data[length-2].digit)
        data[length-1].mobile = 1;
    else
        data[length-1].mobile = 0;
}
void exPrint(Item data[], int length, FILE * fp){//输出
    for (int index = 0; index < length; ++index){
        fprintf(fp, "%d ", data[index].digit);
    }
    fprintf(fp, "\n");
}
void exSwap(Item data[], int i, int j){//交换两个数的位置
    Item tmp = data[i];
    data[i] = data[j];
    data[j] = tmp;
}
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值