编程之美之烙饼问题

// 编程之美之一摞烙饼.cpp : 定义控制台应用程序的入口点。
// 不同的程序会得到不同的结果吗?有个程序能得到不同的结果,但后来证明他的结果是错的
//该算法有点在于在于找最少的交换次数,不是在于用最少的时间进行排序,此算法的排序时间不是最少的。因为算法的查找时间太长了。
#include "stdafx.h"
#include <iostream>
#include <cstdlib>
#include <Math.h>
#include <assert.h>
using namespace std;
#define N 10//7
class Cake{
	int nCakeNum;
	int *nCakeArr;//有用吗?
	int nMaxSwap;//实际进行的最大的交换次数
	int *nCakeResultArr;//存放在哪里进行了交换,存放的是编号
	int *nCakeReverseArr;//几乎所有的操作都是对它进行操作。
	int *nCakeReverseResultArr;//用来记录找到的结果
	int nSearch;

public:
	
	Cake()
	{
		nCakeNum=0;
		nMaxSwap=0;
		nCakeArr=NULL;//没用吧
		nCakeResultArr=NULL;
		nCakeReverseArr=NULL;
		nCakeReverseResultArr=NULL;
		cout<<"in construst"<<endl;
	}

	~Cake()//析构函数自动运行,自动释放对象所占用的资源,不可以再用delete语句了(与编程之美书上不同)。
	{
		//if(nCakeArr!=NULL) delete nCakeArr;
		// if(nCakeResultArr!=NULL) delete nCakeResultArr;
		// if(nCakeReverseArr!=NULL) delete nCakeReverseArr;
		//if(nCakeReverseResultArr!=NULL) delete nCakeReverseResultArr;
	}

	void Run()//int *nCakeArr, int nCakeNum
	{
		//Init(nCakeArr,nCakeNum);
		//nSearch=0;
		Search(0);
	}

	void Output() const
	{
		for(int i=0;i<nMaxSwap;i++)
			cout<<nCakeReverseResultArr[i]<<" ";
		cout<<endl<<"最大的交换次数是:"<<nMaxSwap<<endl;
		cout<<"search times are :"<<nSearch<<endl;
	}

	void PrintArr()
	{
		for(int i=0;i<nCakeNum;i++)
			cout<<nCakeArr[i]<<" ";
		cout<<endl;
		
	}

	void PrintReverseArr()
	{
		for(int i=0;i<nCakeNum;i++)
			cout<<nCakeReverseArr[i]<<" ";
		cout<<endl;
	}

	void Init(int *pCakeArr, int pCakeNum)
	{
		nSearch = 0;
		nCakeNum = pCakeNum;
		nCakeArr = new int[nCakeNum];
		assert(nCakeArr);
		for(int i=0;i<nCakeNum;i++)
		nCakeArr[i] = pCakeArr[i];//init 有用吗?

		nMaxSwap = UpperBound(nCakeNum);

		nCakeResultArr = new int[pCakeNum];
		assert(nCakeResultArr);

		nCakeReverseResultArr = new int[nMaxSwap];
		assert(nCakeReverseResultArr);

		nCakeReverseArr = new int[nCakeNum];
		assert(nCakeReverseArr);
		for(int i=0;i<nCakeNum;i++)
		nCakeReverseArr[i] = pCakeArr[i];//init
	}
private:
	int UpperBound(int pCakeNum)
	{
		return 2*(pCakeNum-2)+1;//原来是2*(pCakeNum-1) 改完这search times 由原来的715减少到589
	}
	
	int LowerBound(int *pCakeArr, int pCakeNum)
	{
		int num=1;//应该是1.因为当最后一个不在其有序时对应的位置时,还要多翻转一次,当这由0改成1后,search times 由原来的4081减少到715
		for(int i=1;i<pCakeNum;i++)
		{
			if((pCakeArr[i]-pCakeArr[i-1]==1)||(pCakeArr[i]-pCakeArr[i-1]==-1))
				;
			else
			num++;
		}
		return num;
	}

	bool IsSorted(int *pCakeArr, int pCakeNum)
	{
		for(int i=1;i<pCakeNum;i++)
		{
			if(pCakeArr[i]<pCakeArr[i-1])
			return 0;
		}
		return 1;
	}

	void Reverse(int *nCakeReverseArr,int begin,int end)// operate nCakeReverseArr
	{
		int temp;
		assert(begin<end);
		for(int i=begin,j=end;i<j;i++,j--)
		{
			temp=nCakeReverseArr[i];
			nCakeReverseArr[i]=nCakeReverseArr[j];
			nCakeReverseArr[j]=temp;
		}
		return;
	}

	void Search(int step)
	{
		nSearch++;
		int estimate=LowerBound(nCakeReverseArr,nCakeNum);
		if(estimate+step>nMaxSwap||step>=nMaxSwap) //加后面的或语句运行次数4081,不加4129
		{
			return ;
		}

		if(IsSorted(nCakeReverseArr,nCakeNum))
		{
			if(step<nMaxSwap)//此算法找最少的翻转次数,不是最小的排序时间。解释:如果数组已经是有序的了,并且当前的步骤少于最大的翻转次数,更新当前的翻转次数,并把当前的结果记录下来。
			{
				nMaxSwap = step;
				for(int i=0;i<nMaxSwap;i++)
				nCakeReverseResultArr[i]=nCakeResultArr[i];//为什么用nCakeReverseResultArr?因为nCakeResultArr本函数返回后还会变,所以不能用其存储最后的结果
			}//若果当前的翻转次数没有原来的少,不更新,只是返回。
			return ;
		}
		for(int i=1;i<nCakeNum;i++)
		{
			Reverse(nCakeReverseArr,0,i);
			nCakeResultArr[step]=i;//保存结果,记录从哪开始翻转的
			Search(step+1);
			Reverse(nCakeReverseArr,0,i);
		}
		return ;
	}
};
//myPizza
int _tmain(int argc, _TCHAR* argv[])
{
	Cake cake1;
	//int arrb[N]={7,3,5,4,2,1,6};
	int arrb[N]={5,6,1,2,3,4,9,8,7,0};
	int *arr = new int[N];
	for(int i=0;i<N;i++)
	{
		arr[i]=arrb[i];
	}
	cake1.Init(arr,N);
	cake1.PrintArr();
	cake1.Run();
	cake1.PrintReverseArr();//作为 递归的数组 遍历所有的分支 到最后没有变化 只是在遍历时把符合条件的存储起来
	cake1.Output();
	//cake1.PrintArr();
	delete [] arr;// 可以不用delete语句删除,不会报错
	system("pause");
	 return 0;
}
/*

//1.3_pancake_1.cpp   by  flyinghearts#qq.com
#include<iostream>
#include<iomanip>
#include<vector>
#include<algorithm>
using namespace std;

class Pancake{
  vector<int> cake;            //当前各个烙饼的状态
  vector<int> cake_swap;       //每次翻转的烙饼位置
  vector<int> result;          //最优解中,每次翻转的烙饼位置
  vector<int> cake_order;      //第step+1次翻转时,翻转位置的优先顺序
  int max_size;                //预分配数组大小
  int min_swap;                //最优解的翻转次数
  int min_swap_init;           //最优解的翻转次数初始值
  int count_search;            //search_cake被调用次数
  int count_reverse;           //reverse_cake被调用次数
  int cake_size;               //要处理的烙饼数组大小
  const int *cake_old;         //要处理的原烙饼数组
  bool not_turn_back;          //是否允许翻回上一个状态
  
  void search_cake(int size, int step, int least_swap_old);
  void reverse_cake(int index); //翻转0到index间的烙饼
  Pancake(const Pancake&);
  Pancake& operator=(const Pancake&);

public:
  Pancake(int size=0):max_size(0) { init(size); }
  void init(int size=0);
  void print() const;
  void process();               //显示最优解,翻转过程
  int run(const int cake_arr[], int size, bool not_turn_back_=1, bool show=1);
};


void Pancake::init(int size)
{
  if (size<=0) size=16;
  if (size>max_size){
    max_size=size;
    cake.resize(size);
    cake_swap.resize(size*2);
    result.resize(size*2);
    cake_order.resize(size*size*2);
  }
  min_swap=0;
  min_swap_init=0;
  count_search=0;
  count_reverse=0;
  cake_size=0;
  cake_old=NULL;
  not_turn_back=true;
}

void Pancake::print() const
{
  if (min_swap>0){
    if (not_turn_back) cout<< "turn back to last state: disallowed.\n";
    else cout<<  "turn back to last state: allowed.\n";
    cout<< "minimal_swap initial: "<< min_swap_init<< "  final: "<< min_swap
        << "\nsearch/reverse function was called: "<< count_search
        << "/"<< count_reverse<< " times\nsolution: ";
    for (int i=0;i<min_swap; ++i) cout<< result[i]<< " ";
    cout<< "\n\n";
  }
}

void Pancake::process()
{
  if (min_swap>0 && cake_size>0 && cake_old != NULL){
    cake.assign(cake_old, cake_old+cake_size);
    int i,j;
    const int WIDTH=3;
    cout<< "old:     ";
    for (j=0; j<cake_size; ++j) cout<< setw(WIDTH)<< cake[j]<<" ";
    cout<<"\n";
    for (i=0; i<min_swap; ++i){
      reverse_cake(result[i]);
      cout<< setw(WIDTH)<< i+1<< "-"<< setw(WIDTH)<< result[i]<<": ";
      for (j=0; j<cake_size; ++j) cout<< setw(WIDTH)<< cake[j]<<" ";
      cout<<"\n";
    }
    cout<<"\n\n";
  }
}

void Pancake::reverse_cake(int index)
{
   ++count_reverse;
   int *beg=&cake[0], *end=&cake[0]+index;
   int tmp;
   while(beg<end){
     tmp = *beg;
     *beg++ = *end;
     *end-- = tmp;
   }
}

int Pancake::run(const int cake_arr[], int size, bool not_turn_back_, bool show)
{
  count_search=0;
  count_reverse=0;
  min_swap=0;
  not_turn_back = not_turn_back_;
  cake_size=0;
  cake_old=NULL;  
  if (cake_arr==NULL || size<=1) return 0;
  while (size>1 && size-1==cake_arr[size-1]) --size; //去除末尾已就位的烙饼
  if (size<=1) return 0;

  if (size>max_size) init(size+16);
  cake.assign(cake_arr,cake_arr+size);
  cake_size=size;
  cake_old=cake_arr;

  int i, least_swap=0, sz=size-1, *p=&result[0];
  while (sz>0){  //先计算一个可能解
    for (i=0; i<=sz; ++i)
      if (cake[i]==sz) break;
    if (i!=0){
      reverse_cake(i);
      *p++=i;         //result.push_back(i);
      ++min_swap;
    }
    reverse_cake(sz);
    *p++=sz--;         //result.push_back(sz);
    ++min_swap;
    while(sz>0 && sz==cake[sz]) --sz;
  }

  cake.assign(cake_arr,cake_arr+size);     //恢复原来的数组
  cake.push_back(size);              //多放一个烙饼,避免后面的边界判断
  cake_swap[0]=0;                    //为方便起见,假设第0步翻转的烙饼编号为0
  for (i=0,least_swap=0; i<size; ++i)
    if (cake[i]-cake[i+1]+1u >2) least_swap++;
    //等同于if (cake[i]-cake[i+1]>1 || cake[i]-cake[i+1]<-1) least_swap++;
  min_swap_init=min_swap;
  if (least_swap != min_swap)
     search_cake(size,0,least_swap);
  if (show) print();
  return min_swap;
}

void Pancake::search_cake(int size, int step, int least_swap_old)
{
  ++count_search;
  while (size>1 && size-1==cake[size-1]) --size;  //去除末尾已就位的烙饼
  int least_swap=least_swap_old;

  for (int pos=1, last_swap=cake_swap[step++]; pos<size; ++pos){
    if (not_turn_back && pos==last_swap) continue;    //是否翻回上个状态
    least_swap = least_swap_old ;
    if (cake[pos]-cake[pos+1]+1u<=2) ++least_swap;
    if (cake[0]-cake[pos+1]+1u<=2) --least_swap;
    if (least_swap+step >= min_swap) continue;
    cake_swap[step]=pos;
    if (least_swap == 0){
      result.assign(&cake_swap[1],&cake_swap[1]+step+1);
      min_swap= step;
      return;
    }
    reverse_cake(pos);
    search_cake(size,step,least_swap);
    reverse_cake(pos);
  }
}

int main()
{
  //? int aa[10]={3,2,1,6,5,4,9,8,7,0};
  int aa[6]= {3,5,2,6,1,4};//此时 改程序不对
  Pancake cake(16);
  //? cake.run(aa,10);
  //? cake.run(aa,10,0);
    cake.run(aa,6);
   cake.run(aa,6,0);
  cake.process();

 //遍历求第n个烙饼数
  const int N=8;
  int i,j,max=0,tmp;
  int arr[N];
  for (j=1;j<=N;++j){
    for (i=0; i<j; ++i) arr[i]=i;
    max=0;
    while(next_permutation(arr,arr+j)){
      tmp=cake.run(arr,j,1,0);
      if (tmp>max) max=tmp;
    }
    cout<<j<<" "<<max<<endl;
  }
	system("pause");
}
*/

http://blog.csdn.net/tianshuai11/article/details/7659673 他的程序确实有问题

    原文作者:littlestream9527
    原文地址: https://blog.csdn.net/littlestream9527/article/details/7981494
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞