烙饼排序

 

星期五的晚上,一帮同事在希格玛大厦附近的“硬盘酒吧”多喝了几杯。程序员多喝了几杯之后谈什么呢?自然是算法问题。有个同事说:“我以前在餐馆打工,顾客经常点非常多的烙饼。店里的饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小次序摆好——小的在上面,大的在下面。由于我一只手托着盘子,只好用另一只手,一次抓最上面的几块饼,把它们上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了。我后来想,这实际上是个有趣的排序问题:假设有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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值