题目
给定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;
}