排序问题

j8daxue 2011-02-14 03:57:14
http://soj.me/1142

Description
通常我们对一个长度为n(n≤24)的整数数列进行排序操作,其实就是讲他们按照从小到大的顺序重整。一般情况下我们可以比较任意两个数之间的大小并交换他们的位置,但这里我们限制只能数列的某一个前缀序列翻转,除此之外的任何操作都是不允许的。更精确地说,假设数列a1,a2,……,an,一个合法的操作是把数列变为ak,ak-1,……,a2, a1, ak+1, ak+2,……, an,其中1<k≤n。例如:数列3 2 1 4,可能的操作有三种,分别是2 3 1 4、1 2 3 4、4 1 2 3。

你任务是求出一个序列用上面的方法排序至少需要多少步。

Sample Input
4
3 2 1 4

Sample Output
1
提示,只需要一步就可以完成排序:3 2 1 4  1 2 3 4。



第一眼没想过搜索,不过看到有人搜索通过了。
觉得方案是每次找到最大的数,翻转至首,然后到末尾。
然后确定下次找最大数字(除去已经归位的)的在数组中最长长度。
流程如:
1243->4213->3124->2134->1234
15786->87516->61578->51678->15678
WA@TEST2,不知道想法是错的还是没写好。

//0~count逆序字符串
bool reverse_str(int count,char* str,char max)
{
int l = 0;
int h = count - 1;
bool bRet = (str[0] == max);
while(l < h)
{
char tmp = str[l];
str[l] = str[h];
str[h] = tmp;
l++;h--;
}
cout<<str<<endl;
return bRet;
}
int cmp(const void* a,const void* b)
{
return *(char*)a - *(char*)b;
}
//确定最大数字位置,返回翻转长度
//ready. 已有多少数据归位.
int check_bit(char* str,int len,char& max,int ready)
{
max = str[0];
int idx = 0;
for(int i = 1 ; i < len - ready ; i ++)
{
if(max < str[i])
{
max = str[i];
idx = i;
}
}
if(idx == 0)
return len - ready;
if(idx == len - ready - 1)
return -1;
return idx + 1;
}
//是否目标状态
//从右到左,已经归位的数字个数.
int check_ready(char* str,char* dest,bool& bsame)
{
int len = strlen(str);
int c = 0;
bsame = true;
for(int i = len - 1; i >= 0 ; i --)
{
if(str[i] == dest[i])
c++;
else
{
bsame = false;
break;
}
}
return c;
}
void slove(char* str)
{
int bit;
int c = 0;
int len = strlen(str);
if(len == 1)
{
cout<<"0"<<endl;
return;
}
bool same = false;
char buf[26];
strcpy(buf,str);
qsort(buf,len,sizeof(char),cmp);

int ready = check_ready(str,buf,same);
char max;
if(ready == len)
{
cout<<"0"<<endl;
return;
}
while(ready != len - 1)
{
bit = check_bit(str,len,max,ready);//找最大数字以及翻转长度
if(bit == -1)
{
ready++;
continue;
}
reverse_str(bit,str,max);//翻转
c++;
ready = check_ready(str,buf,same);//匹配
if(same)
break;
}
cout<<c<<endl;
}
int main()
{
int n;
cin>>n;
char* buf = new char[n + 1];
for(int i = 0 ; i < n ; i ++)
cin>>buf[i];
buf[n] = '\0';
slove(buf);
return 0;
}
...全文
229 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
KingWolfOfSky 2011-02-17
  • 打赏
  • 举报
回复
好一点的解放,翻转次数少

#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX_LEN 30

int data[MAX_LEN+1];
int check[MAX_LEN+1];
int flips[2*MAX_LEN];

char inbuf[512];
FILE *fpi, *fpo;

int revFindFlips(int low, int high, int *pVals, int *pFlips, int *pNFlips);

int ParseInbuf(char *pBuf, int *pVals)
{
int nvals, curval, len, pos;
int inval;

len = strlen(pBuf);
pos = 0;
/* skip leading spaces */
while(isspace(pBuf[pos]))
{
pos++;
if(pos >= len)
{
return -4;
}
}
for(curval = 0; curval <= MAX_LEN ; curval++)
{
check[curval] = -1;
}
/* now point at non-whitespace */
/* get count */
if(sscanf(&(pBuf[pos]), "%d", &nvals) != 1)
{
return -5;
}
if(nvals > MAX_LEN)
{
return -9;
}
for(curval = 0; curval < nvals ; curval++)
{
/* skip over last value */
while(!isspace(pBuf[pos]))
{
pos++;
if(pos >= len)
{
return -6;
}
}
/* skip over spaces */
while(isspace(pBuf[pos]))
{
pos++;
if(pos >= len)
{
return -7;
}
}
/* read integer value */
if(sscanf(&(pBuf[pos]), "%d", &inval) != 1)
{
return -8;
}
/* verify */
if((inval < 1) || (inval > nvals))
{
return -11;
}
if(check[inval] >= 0)
{
return -12;
}
check[inval] = curval;
pVals[curval] =inval;
}
return nvals;
}

/* flip first k values */
void flip(int k, int *pVals)
{
int i, j, tmp;
for(i = 0, j = k-1; i < k/2 ; i++, j--)
{
tmp = pVals[i];
pVals[i] = pVals[j];
pVals[j] = tmp;
}
}

/*
* recursively figure out the flips
* if high val is on the bottom of current stack
* leave it there and recursively call findFlips with high-1
* else if high val is on top, flip it to the bottom
* and recursively call findFlips with high-1
* else if low val is on the bottom
* recursively call revFindFlips with low+1 to get in rev order
* then flip the lot
* else
* find location of high value
* flip it to the top
* flip the whole stack to get it to the bottom
* and recursively call findFlips with high-1
*/
int findFlips(int low, int high, int *pVals, int *pFlips, int *pNFlips)
{
int nleft, i, pos, ret;

nleft = high - low + 1;
if(nleft == 1)
{
if(pVals[0] != high)
{
return -1;
}
else
{
return 0;
}
}
else if(nleft == 2)
{
if((pVals[0] == low) && (pVals[1] == high))
{
return 0;
}
else if((pVals[1] == low) && (pVals[0] == high))
{
flip(2, pVals);
pFlips[*pNFlips] = 2;
(*pNFlips)++;
return 0;
}
else
{
return -2;
}
}
if(pVals[nleft-1] == high)
{ /* already in the right place on to the next */
return(findFlips(low, high-1, pVals, pFlips, pNFlips));
}
else if(pVals[0] == high)
{ /* in first place flip to correct pos */
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return(findFlips(low, high-1, pVals, pFlips, pNFlips));
}
else if(pVals[nleft-1] == low)
{
ret = revFindFlips(low+1, high, pVals, pFlips, pNFlips);
if(ret != 0)
{
return ret;
}
/* now in reverse order, flip the whole thing */
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return 0;
}
else
{
pos = -1;
for(i = 0; i < nleft ; i++)
{
if(pVals[i] == high)
{
pos = i+1;
break;
}
}
if(pos <= 0)
{ /* cannot find it?? */
return -30;
}
if(pos == nleft)
{ /* already in the correct place */
return(findFlips(low, high-1, pVals, pFlips, pNFlips));
}
else if(pos == 1)
{ /* in first place, flip to k */
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return(findFlips(low, high-1, pVals, pFlips, pNFlips));
}
else
{ /* first flip from cur pos to 1 then to k */
flip(pos, pVals);
pFlips[*pNFlips] = pos;
(*pNFlips)++;
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return(findFlips(low, high-1, pVals, pFlips, pNFlips));
}
}
}

/*
* recursively figure out the flips to get stack in reverse order
* if low val is on the bottom of current stack
* leave it there and recursively call revFindFlips with low+1
* else if low val is on top, flip it to the bottom
* and recursively call revFindFlips with low+1
* else if high val is on the bottom
* recursively call findFlips with high-1 to get in fwd order
* then flip the lot
* else
* find location of low value
* flip it to the top
* flip the whole stack to get it to the bottom
* and recursively call revFindFlips with low+1
*/
int revFindFlips(int low, int high, int *pVals, int *pFlips, int *pNFlips)
{
int nleft, i, pos, ret;

nleft = high - low + 1;
if(nleft == 1)
{
if(pVals[0] != high)
{
return -1;
}
else
{
return 0;
}
}
else if(nleft == 2)
{
if((pVals[1] == low) && (pVals[0] == high))
{
return 0;
}
else if((pVals[0] == low) && (pVals[1] == high))
{
flip(2, pVals);
pFlips[*pNFlips] = 2;
(*pNFlips)++;
return 0;
}
else
{
return -2;
}
}
if(pVals[nleft-1] == low)
{ /* already in the right place on to the next */
return(revFindFlips(low+1, high, pVals, pFlips, pNFlips));
}
else if(pVals[0] == low)
{ /* at top, flip to bottom */
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return(revFindFlips(low+1, high, pVals, pFlips, pNFlips));
}
else if(pVals[nleft-1] == high)
{ /* right place for fwd */
ret = findFlips(low, high-1, pVals, pFlips, pNFlips);
if(ret != 0)
{
return ret;
}
/* now in fwd order, flip the whole thing to get reverse */
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return 0;
}
else
{
pos = -1;
for(i = 0; i < nleft ; i++)
{
if(pVals[i] == low)
{
pos = i+1;
break;
}
}
if(pos <= 0)
{ /* cannot find it?? */
return -30;
}
if(pos == nleft)
{ /* already in the correct place */
return(revFindFlips(low+1, high, pVals, pFlips, pNFlips));
}
else if(pos == 1)
{ /* in first place, flip to k */
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return(revFindFlips(low+1, high, pVals, pFlips, pNFlips));
}
else
{ /* first flip from cur pos to 1 then to k */
flip(pos, pVals);
pFlips[*pNFlips] = pos;
(*pNFlips)++;
flip(nleft, pVals);
pFlips[*pNFlips] = nleft;
(*pNFlips)++;
return(revFindFlips(low+1, high, pVals, pFlips, pNFlips));
}
}
}

int CheckResult(int nvals, int *pVals)
{
int i;
for(i = 0; i < nvals ; i++)
{
if(pVals[i] != i+1)
{
fprintf(stderr, "CheckResult: val[%d] = %d\n",
i+1, pVals[i]);
return -1;
}
}
return 0;
}

void PrintFlips(int nflips, int *pFlips)
{
int i;

if(nflips == 0)
{
printf("0\n");
return;
}
fprintf(fpo, "%d ", nflips);
for(i = 0; i < nflips - 1; i++)
{
fprintf(fpo, "%d ", pFlips[i]);
}
fprintf(fpo, "%d\n", pFlips[nflips - 1]);
}

int main()
{
int dataset, ncnt, nflips, ret;
fpi = fopen("d.in", "rt");
if(fpi == NULL){
fprintf(stderr, "Can not open input d.in\n");
return(1);
}
fpo = stdout;
if(fpo == NULL){
fprintf(stderr, "Can not open output d.out\n");
return(2);
}

dataset = 0;
if(fgets(&(inbuf[0]), 512, fpi) == NULL)
{
fprintf(stderr, "read failed on first dataset\n");
return -20;
}
while(1)
{
ncnt = ParseInbuf(&(inbuf[0]), &(data[0]));
if(ncnt <= 0)
{ /* 0 means end of data <0 means error */
return ncnt;
}
nflips = 0;
ret = findFlips(1, ncnt, &(data[0]), &(flips[0]), &nflips);
if(ret != 0)
{
return ret;
}
if(CheckResult(ncnt, &(data[0])) != 0)
{
return -21;
}
PrintFlips(nflips, &(flips[0]));
dataset++;
if(fgets(&(inbuf[0]), 512, fpi) == NULL)
{
fprintf(stderr, "read failed on dataset %d\n", dataset + 1);
return -20;
}
}
fclose(fpi);
return 0;
}
KingWolfOfSky 2011-02-17
  • 打赏
  • 举报
回复
针对 http://poj.org/problem?id=2275的简单代码

#include <stdio.h>
#include <stdlib.h>
#include <list>
using namespace std;

list<int> steps;
list<int>::iterator it;
void flip(int n,int* cakes)
{
int *i,*j,t;
if(n==1)return;
if(*cakes==n)
{
steps.push_back(n);
i=cakes+n-1;j=cakes;
while(j<i)
{
t=*i;
*i=*j;
*j=t;
++j;--i;
}
flip(n-1,cakes);
}
else
{
j=i=cakes;
while(*i!=n)++i;
if(n==(i-j+1)){flip(n-1,cakes);return;}
steps.push_back(i-cakes+1);
while(j<i)
{
t=*i;
*i=*j;
*j=t;
++j;--i;
}
steps.push_back(n);
i=cakes+n-1;j=cakes;
while(j<i)
{
t=*i;
*i=*j;
*j=t;
++j;--i;
}
flip(n-1,cakes);
}
}
int main(int argc,char* argv[])
{
int n,*Pancakes,*tmp,i;
while(scanf("%d",&n),i=n,n!=0)
{
steps.clear();
tmp=Pancakes=(int*)malloc(n*sizeof(int));
while(i--)scanf("%d",tmp++);
flip(n,Pancakes);
printf("%d ",steps.size());
for(it=steps.begin();it!=steps.end();++it)printf("%d ",*it);
printf("\n");
}
return 0;
}
KingWolfOfSky 2011-02-17
  • 打赏
  • 举报
回复
看过这个题目两个出处
第一个是 《编程之美》中的 1.3 一摞烙饼的排序
第二个是 http://poj.org/problem?id=2275
都是烧饼问题
keeya0416 2011-02-17
  • 打赏
  • 举报
回复
《编程之美》中的 1.3 一摞烙饼的排序
yaoweijq 2011-02-15
  • 打赏
  • 举报
回复
这不编程之美上翻饼题的另一种形式么?
原书上正解是暴力穷举
还给出了一堆上下界
还说盖茨发表的唯一学术论文就是有关于这个的
哈哈
j8daxue 2011-02-14
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 pmars 的回复:]
例:
5
1 4 3 2 5
按lz的方法
14325->41325->23145->32145->12345
这样呢:
14325->23415->43215->12345
可见问题。。。
[/Quote]
果然思路不对,只能搜索吗?这题
pmars 2011-02-14
  • 打赏
  • 举报
回复
例:
5
1 4 3 2 5
按lz的方法
14325->41325->23145->32145->12345
这样呢:
14325->23415->43215->12345
可见问题。。。

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧