烙饼排序的实现

真是个有意思的题目,烙饼,lb,鲁滨,哈哈。决定下个11账号就叫 烙饼_刘 了。

书上的思路其实很简单,用了状态空间搜索里面最常见的分支限界法,用循环和递归穷举所有可能的情况,然后约束上界和下界来进行剪枝。上界越小,下界越大,剪枝效果越好。接口如下:

class Lbsort{
	public:
		Lbsort():m_laobings(0), m_pCount(0), m_swapInfo(0), t_laobings(0), t_swapInfo(0), max_swapCount(0), m_searchTimes(0){}
		~Lbsort(){
			if(m_laobings != NULL){
				delete m_laobings;
				m_laobings = 0;
			}
			if(m_swapInfo != NULL){
				delete m_swapInfo;
				m_swapInfo = 0;
			}
			if(t_laobings != NULL){
				delete t_laobings;
				t_laobings = 0;
			}
			if(t_swapInfo != NULL){
				delete t_swapInfo;
				t_swapInfo = 0;
			}
		}
		void doSort(int*, int);//主接口
		void printResults();//打印结果
	private:
		void search(int);//主排序
		int upbound(int);//初始化时返回上界
		int lowbound(int*, int);//剪枝时使用的下界
		void init(int*, int);//系统状态的初始化
		bool isSorted(int*, int);//判断是否已经排序完成
		void doReverse(int*, int);//翻转最上面那部分烙饼
		
		int* m_laobings;//存放原始烙饼的编号
		int m_pCount;//存放原始烙饼的数目
		int* m_swapInfo;//存放每次交换的位置的最终结果 
		int* t_laobings;//存放烙饼编号中间结果
		int* t_swapInfo;//存放交换位置的中间结果
		int max_swapCount;//存放交换次数的上届
		int m_searchTimes;//存放当前的交换次数
};
实现也非常简单:

void Lbsort::doSort(int* laobings, int count){
	//Assert(laobings != NULL && count > 0);
	init(laobings, count);
	search(0);
} 

void Lbsort::printResults(){
	using std::cout;
	using std::endl;
	cout<<"Total search times: "<<m_searchTimes<<endl;
	cout<<"Min swap times: "<<max_swapCount<<endl;
	for(int i=0;i<max_swapCount;i++)
		cout<<m_swapInfo[i]<<" ";
	cout<<endl;
}

void Lbsort::search(int step){
	++m_searchTimes;
	int tp_lowbound = lowbound(t_laobings, m_pCount);
	if(tp_lowbound+step>=max_swapCount)
		return;
	if(isSorted(t_laobings, m_pCount)){
		if(step < max_swapCount){
			max_swapCount = step;
			memcpy(m_swapInfo, t_swapInfo, max_swapCount*sizeof(int));
		}
		return;
	}
	for(int i=1;i<m_pCount;i++){
		doReverse(t_laobings, i);
		t_swapInfo[step] = i;
		search(step+1);
		doReverse(t_laobings, i);
	} 
}

int Lbsort::upbound(int count){
	return 2*(count - 1);
}

int Lbsort::lowbound(int* laobings, int count){
	int tp_low = 0, t;
	for(int i=count-1;i>0;i--){
		t = laobings[i] - laobings[i-1];
		if(!(t == 1 || t == -1)){
			tp_low++;
		}
	}
	return tp_low;
}

void Lbsort::init(int* laobings, int count){
	m_laobings = new int[count];
	t_laobings = new int[count];
	max_swapCount = upbound(count);
	m_swapInfo = new int[max_swapCount];
	t_swapInfo = new int[max_swapCount];
	//Assert(m_laobings != NULL && t_laobings != NULL && m_swapInfo != NULL && t_swapInfo != NULL);
	memcpy(m_laobings, laobings, count*sizeof(int));
	memcpy(t_laobings, laobings, count*sizeof(int));
	m_pCount = count;
	m_searchTimes = 0;
}

bool  Lbsort::isSorted(int* laobings, int count){
	for(int i=1;i<count;i++){
		if(laobings[i-1] > laobings[i])
			return false;
	}
	return true;
}

void Lbsort::doReverse(int* laobings, int pos){
	for(int i=0, j=pos;i<j;i++,j--){
		int tp = laobings[i];
		laobings[i] = laobings[j];
		laobings[j] = tp;
	}
}
分支限界的复杂度是很高的,书上提到了动态规划但是没有实现,上网搜了一下,有人分析出这个问题是不能使用动态规划和贪心的,主要原因是不满足最优子结构,即当前的最优解并不一定是全局的最优解。在这种情况下,翻转需要最小的次数,并不代表它可以带来全局的最少翻转次数。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值