星期五的晚上,一帮同事在希格玛大厦附近的“硬盘酒吧”多喝了几杯。程序员多喝了几杯之后谈什么呢?自然是算法问题。有个同事说:“我以前在餐馆打工,顾客经常点非常多的烙饼。店里的饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小次序摆好——小的在上面,大的在下面。由于我一只手托着盘子,只好用另一只手,一次抓最上面的几块饼,把它们上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了。我后来想,这实际上是个有趣的排序问题:假设有n块大小不一的饼,那最少要翻几次,才能达到最后大小有序的结果呢?你能否写出一个程序,对于n块大小不一的烙饼,输出最优化的翻饼过程呢?
这是一个求最优化的问题,此题不能用动态规划编写。因为其没有最优子结构,所以只有遍历完所有的情况,挑选其中最优的。但是在搜索的过程中可以添加减支函数,减少搜索的次数。关键是递归函数的编写。
for(int i=1;i<len;++i)
{
if(count!=0&&temp[count]==i)
continue;
reverse(data,i);
temp[count+1]=i;
pee(data,len,count+1);
reverse(data,i);//回到上一个状态
}//递归的翻转过程,搜索树的遍历
还有就是减支函数的设计,根据当前的数组的值,可以求出到最后的状态至少需要翻转的次数,所以可以通过这个设计减支函数,减支函数的设计的优劣直接影响到搜索的效率。
代码如下:
#include<iostream>
using namespace std;
int min;//记录所需要翻转的最少的次数
int *temp,*result;//temp数组保存中间的翻转步骤的结果,result保存翻转的步骤
int Lowbound(int *parray,int cakenum)
{
int t=0,ret=0;
for(int i=0;i<cakenum-1;i++)
{
t=parray[i]-parray[i+1];
if((t==1)||(t==-1))
{
}
else
ret++;
}
return ret;
}//烙饼在当前状态的最少需要的翻转次数
void reverse(int *data,int index)
{//翻转函数 将0---index翻转
int i=0,j=index;
int temp;
while(i<j)
{
temp=data[i];
data[i]=data[j];
data[j]=temp;
++i;
--j;
}
}//翻转操作
bool over(int *data,int len)
{
for(int i=1;i<len;++i)
if(data[i-1]>data[i])
return false;
if(i==len)
return true;
return false;
}//判断翻转的结果是否达到要求
int cnt=0;//记录翻转的总次数
void pee(int *data,int len,int count=0)
{
cnt++;
int Estimate=Lowbound(data,len);
if((count+Estimate)>min)
return;//减支函数
if(over(data,len))
{
if(min>count)
{
min=count;
memcpy(result,temp,sizeof(int)*(2*(len)));
cout<<"当前最少搜索次数cur_min="<<min<<endl;
for(int i=1;i<=min;i++)
{
cout<<result[i]+1<<" ";
}
cout<<endl;
}
return;
}
for(int i=1;i<len;++i)
{
if(count!=0&&temp[count]==i)
continue;//若搜索完一步之后,立刻回到了上一个状态,则不需要继续搜索,直接去掉这一支,也算是一个减支函数
reverse(data,i);
temp[count+1]=i;
pee(data,len,count+1);
reverse(data,i);
}//递归求翻转过程,其实是一棵搜索树
}
void main()
{
int Cake_num;//烙饼的个数
cout<<"请输入烙饼的个数:"<<endl;
cin>>Cake_num;
cout<<"请依次输入烙饼的大小:"<<endl;
int *Cake_array=new int[Cake_num];//存放烙饼的数组
temp=new int[2*(Cake_num)];
result=new int[2*(Cake_num)];
for(int i=0;i<Cake_num;i++)
{
cin>>Cake_array[i];
}
for(i=0;i<2*(Cake_num-1);i++)
{
temp[i]=0;
result[i]=0;
}
min=2*(Cake_num);
pee(Cake_array,Cake_num);
cout<<"-------------------"<<endl;
cout<<"最少的翻转次数max="<<min<<endl;
cout<<"翻转的过程:"<<endl;
for(i=1;i<=min;i++)
{
cout<<result[i]+1<<" ";
}
cout<<endl;
cout<<"Total Run Times: "<<cnt<<endl;
}