编程之美——一摞烙饼的排序(暴搜+剪枝)

题目

分析

深度优先搜索遍历每一种情况,去翻转次数最小的,当然,还要加一些剪枝,毕竟O(nn)的时间复杂度。

代码

C风格

复制代码
 1 /**** 前缀排序 ****/
 2 #include<stdio.h>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 
 7 const int maxn = 100 + 10;
 8 int n, arr[maxn];            //烙饼个数和烙饼数组
 9 int arr_cmp[maxn];
10 int arr_tmp[maxn];                //记录初始数组
11 
12 int search_times = 0;        //总搜索次数
13 int max_swap;            //最小交换次数
14 int arr_swap[2 * maxn];        //最终翻转方案
15 int tarr_swap[2 * maxn];    //当前翻转方案
16 
17 void Init()
18 {
19     for (int i = 0; i < n; i++)  arr_tmp[i] = arr_cmp[i] = arr[i];
20     sort(arr_cmp, arr_cmp + n);
21     max_swap = 2 * (n - 1);
22 }
23 
24 void Reverse(int* arr,int start, int end)
25 {
26     for (int i = start, j = end; i < j; i++, j--)
27         swap(arr[i], arr[j]);
28 }
29 
30 int LowerBound()
31 {
32     int ret = 0;
33     for (int i = 1; i < n; i++)
34         if (arr[i - 1] > arr[i])  ret++;
35     return ret;
36 }
37 
38 bool IsSort()
39 {
40     for (int i = 0; i < n; i++)
41if(arr_cmp[i]!= arr[i])returnfalse;42returntrue;43}4445voidSearch(int step)46{47     search_times++;4849if(IsSort())//已排好序50{51if(step < max_swap)52{53             max_swap = step;54for(int i =0; i < max_swap;i++)  arr_swap[i]= tarr_swap[i];55}56}5758if((step +LowerBound())> max_swap)return;5960for(int i =1; i <= n; i++)61{62Reverse(arr,0, i);63         tarr_swap[step]= i;64Search(step +1);65Reverse(arr,0, i);66}67}6869voidPrint()70{71     printf("搜索次数:%d\n", search_times);72     printf("翻转次数: %d\n", max_swap);73for(int i =0; i < max_swap; i++)  printf("%d ", arr_swap[i]);74     printf("\n具体的翻转情况:\n");75for(int i =0; i < max_swap; i++)76{77Reverse(arr_tmp,0, arr_swap[i]);78for(int j =0; j < n; j++)  printf("%d ", arr_tmp[j]);79         printf("\n");80}81}8283int main()84{85     scanf("%d",&n);86for(int i =0; i < n; i++)  scanf("%d",&arr[i]);87Init();88Search(0);89Print();90}
复制代码

C++风格

复制代码
  1 #include<stdio.h>
  2 #include<cstring>
  3 #include<cassert>         //assert宏的原型定义在<assert.h>中
  4 #include<algorithm>
  5 using namespace std;
  6 
  7 class laobing
  8 {
  9 private:
 10     int* m_CakeArray;        //烙饼信息数组
 11     int m_nCakeCnt;            //烙饼个数
 12     int m_nMaxSwap;            //最多翻转次数
 13     int* m_SwapArray;        //最终翻转烙饼位置
 14     int* m_ReverseCakeArray;        //当前烙饼数组
 15     int* m_ReverseCakeArraySwap;    //当前翻转烙饼位置
 16     int m_nSearch;            //搜索次数
 17 
 18 public:
 19     laobing()
 20     {
 21         int m_CakeCnt = 0;
 22         int m_nMaxSwap = 0;
 23     }
 24     ~laobing()
 25     {
 26         if (m_CakeArray != NULL)  delete m_CakeArray;
 27         if (m_SwapArray != NULL)  delete m_SwapArray;
 28         if (m_ReverseCakeArray != NULL)  delete  m_ReverseCakeArray;
 29         if (m_ReverseCakeArraySwap != NULL)  delete m_ReverseCakeArraySwap;
 30     }
 31 
 32     //计算烙饼翻转信息
 33     //pCakeArray    存储烙饼数组
 34     //nCakeCnt      烙饼个数
 35     void run(int* pCakeArray, int nCakeCnt)
 36     {
 37         Init(pCakeArray, nCakeCnt);
 38         m_nSearch = 0;
 39         Search(0);
 40     }
 41 
 42     //输出交换过程
 43     void OutputArray(int* CakeArray, int nCakeCnt, int* m_SwapArray, int m_nMaxSwap)
 44     {
 45         for (int i =0; i < m_nMaxSwap; i++)//每一次交换46{47Reverse(CakeArray,0, m_SwapArray[i]);48for(int i =0; i < nCakeCnt; i++)  printf("%d ",CakeArray[i]);49             printf("\n");50}51}5253//输出烙饼具体的翻转情况54voidOutput()55{56for(int i =0; i < m_nMaxSwap; i++)  printf("%d ", m_SwapArray[i]);57         printf("\n");58         printf("Search Times: %d\n", m_nSearch);59         printf("Total Times: %d\n", m_nMaxSwap);6061OutputArray(m_CakeArray, m_nCakeCnt, m_SwapArray, m_nMaxSwap);62}63private:64voidInit(int*pCakeArray,int nCakeCnt)65{66assert(pCakeArray != NULL);//其作用是如果它的条件返回错误,则终止程序执行。67assert(nCakeCnt >0);6869//初始化烙饼数组70         m_nCakeCnt = nCakeCnt;71         m_CakeArray =newint[m_nCakeCnt];72assert(m_CakeArray != NULL);73for(int i =0; i < m_nCakeCnt; i++)74             m_CakeArray[i]= pCakeArray[i];7576//设置最多交换次数77         m_nMaxSwap =UpBound(m_nCakeCnt);7879//初始化交换数组结果80         m_SwapArray =newint[m_nMaxSwap];81assert(m_SwapArray != NULL);8283//初始化中间交换结果84         m_ReverseCakeArray =newint[m_nCakeCnt];85for(int i =0; i < m_nCakeCnt; i++)86             m_ReverseCakeArray[i]= m_CakeArray[i];87         m_ReverseCakeArraySwap =newint[m_nMaxSwap];88}8990//寻找当前翻转次数的上界91//n个烙饼,翻转最大的n-2烙饼最多需要2*(n-2)次,剩下的2个最多1次,因而上限值为2*n-3,92//因此,m_nMaxSwap初始值可以取2*n-3+1=2*n-2,这样每步与m_nMaxSwap的判断就可以取大等于号。93intUpBound(int nCakeCnt)94{95return2*(nCakeCnt -1);96}9798//寻找当前翻转次数的下界99intLowerBound(int* pCakeArray,int nCakeCnt)100{101int ret =0;102103//根据当前数组的顺序信息来判断最少需要交换多少次104for(int i =1; i < nCakeCnt; i++)105{106//判断位置相邻的两个烙饼是否是尺寸相邻的107int tmp = pCakeArray[i]- pCakeArray[i -1];108if(tmp ==1|| tmp ==-1)continue;109else  ret++;110}111if(pCakeArray[nCakeCnt -1]!= nCakeCnt -1)  ret++;//判断下界时,如果最大的烙饼不在最后一个位置,则要多翻转一次112return ret;113}114115//排序的主函数116voidSearch(int step)117{118         m_nSearch++;119//// 估算这次搜索所需要的最小交换次数  120int nEstimate =LowerBound(m_ReverseCakeArray, m_nCakeCnt);121if(step + nEstimate >= m_nMaxSwap)return;//剪枝122123//如果已经排好序,直接输出124if(IsSort(m_ReverseCakeArray, m_nCakeCnt))125{126if(step < m_nMaxSwap)127{128                 m_nMaxSwap = step;129for(int i =0; i < m_nMaxSwap; i++)  m_SwapArray[i]= m_ReverseCakeArraySwap[i];130}131return;132}133134//递归进行翻转135for(int i =1; i < m_nCakeCnt; i++)136{137Reverse(m_ReverseCakeArray,0, i);138             m_ReverseCakeArraySwap[step]= i;139Search(step +1);//递归140Reverse(m_ReverseCakeArray,0, i);//回溯141}142}143144//检查是否排好序145boolIsSort(int* pCakeArray,int nCakeCnt)146{147for(int i =1;i < nCakeCnt;i++)148if(pCakeArray[i -1]> pCakeArray[i])returnfalse;149returntrue;150}151152//翻转烙饼信息153voidReverse(int* m_arr,int nBegin,int nEnd)154{155assert(nEnd > nBegin);156157for(int i = nBegin, j = nEnd; i < j; i++, j--)158            swap(m_arr[i], m_arr[j]);159}160};161162constint maxn =100+10;163int n, arr[maxn];164165int main()166{167    laobing lb;168     laobing* p =new laobing();169     scanf("%d",&n);170for(int i =0; i < n; i++)  scanf("%d",&arr[i]);171172     p->run(arr, n);173     p->Output();174175    lb.run(arr, n);176return0;177}
复制代码

参考链接:

https://blog.csdn.net/tianshuai1111/article/details/7659673

http://blog.sina.com.cn/s/blog_a2aa00d70101ewuf.html

https://blog.csdn.net/ML_algorithmResearch/article/details/50405548

posted @ 2019-07-18 19:13  天涯海角路  阅读(209)  评论(0)    收藏  举报