任意次序的n个烙饼最小反转次数求解

简介:

 贴上详细的题目:

       星期五的晚上,一帮微软技术员在希格玛附近的“硬盘酒吧”谈算法问题。有个同事说:   我以前在烙饼店打工,顾客经常端非常多的烙饼。店里的饼大小不一, 我习惯在到达顾客饭桌前,把一摞饼按照大小次序摆好——小的在上面,大的在下面。由于我一只手托着盘子,只好用另一只手,一次抓住最上面的几块饼,把它们 上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了。 
       假设有n块大小不一的烙饼,那最多/最少要翻几次,才能达到最后大小有序的结果呢? 吧台的酒保说:这太难了吧。我有个简单的问题。有一次我烙了三个饼,一个两面都焦了,一
个两面都是金黄色,一个一面是焦的,一面是金黄色,我把它们摞一起,只能看到最上面一个饼的一面,发现是焦的,问最上面这个饼的另一面是焦的概率是多少? 不少喝酒的人脱口而出:1/2! 上面的说法对吗?你能否写出一个程序,对于n块大小不一的烙饼,输出最优化的翻饼过程呢? 
  

 


usings

namespace CakeSorting
{
    
class Program
    
{
        
Vars

        
static void Main(string[] args)
        
{
            Program p 
= new Program();
            p.run();
        }


        
void run()
        
{
            DateTime dt 
= DateTime.Now;
            TimeSpan ts;
            init();
            enumeratQueue(cakes.Count());
            ts 
= DateTime.Now - dt;
            Console.WriteLine(
"\nResult\nMinTime is:{0}\t{1}:{2}:{3}:{4}", minTime, ts.Hours, ts.Minutes, ts.Seconds, ts.Milliseconds);
            Console.ReadLine();
        }


        
void init()
        
{
            
//初始化赋值

            setMaxTime();

            minTime 
= 0;

            cakeArray 
= new int[cakeNum];

            cakeSizeArray 
= new int[cakeNum];

            cakes 
= new Queue<int>();

            steps 
= new Stack<int>();

            
for (int i = 0; i < cakeSizeArray.Length; i++)
            
{
                cakeSizeArray[i] 
= i;
            }
//大饼直径初始化

            
foreach (int i in cakeSizeArray)
            
{
                cakes.Enqueue(i);
            }
//大饼队列化
        }


        
void enumeratQueue(int cn)
        
{
            
if (cn == 1)
            
{
                
int t = cakes.Dequeue();
                cakeArray[
0= t;
                setMaxTime();
                search(
0);
                minTime 
= maxTime > minTime ? maxTime : minTime;
                show();
                cakes.Enqueue(t);
            }


            
for (int i = 0; i < cn; i++)
            
{
                
int t = cakes.Dequeue();
                cakeArray[cn 
- 1= t;
                enumeratQueue(cn 
- 1);
                cakes.Enqueue(t);
            }

        }


        
void search(int step)
        
{
            
if (maxTime < 15 * cakeNum / 14)
                
return;//当此最优解必小于此最劣情况下界时剪枝

            
if (step > maxTime)
                
return;//大于2(n-1)时退出

            
if (step + getLowerTime() > maxTime)
                
return;//最优预计

            
for (int i = 1; cakeArray [i-1]<cakeArray [i]; i++)
            
{
                
if (i == cakeArray.Length - 1)
                
{
                    maxTime 
= step;
                    
return;
                }

            }
//排序成功退出

            
for (int i = 0; i < cakeArray.Length; i++)
            
{
                revert(
0, i);
                search(step
+1);
                revert(
0, i);
            }
//递归穷举所有方案
        }


        
void revert(int begin, int end)
        
{
            
int t = cakeArray[begin];
            
for (int i = begin, j = end; i < j; i++, j--)
            
{
                t 
= cakeArray[i];
                cakeArray[i] 
= cakeArray[j];
                cakeArray[j] 
= t;
            }

        }


        
void show()
        
{
            
foreach (int i in cakeArray)
            
{
                Console.Write(
"{0}\t", i);
            }

            Console.Write(
"\nMaxTime is:{0}\tMinTime is:{1}\n**************************************************\n",maxTime ,minTime);
        }


        
void setMaxTime()
        
{
            
//maxTime = 2 * (cakeNum - 1);
            maxTime = (5 * cakeNum + 5/ 3 < 2 * (cakeNum - 1? (5 * cakeNum + 5/ 3 : 2 * (cakeNum - 1);
        }


        
int getLowerTime()
        
{
            
int count=0;
            
for (int i = 1; i < cakeNum; i++)
            
{
                
if (Math.Abs(cakeArray[i - 1- cakeArray[i]) != 1)
                    count
++;
            }

            
return count;
        }

    }

}

上一篇写了当已知一个烙饼队列,求出其最少反转次数。

这一篇中将求出如题即n个烙饼最坏情况下需要多少次反转。

《编程之美》中给出目前最优最大下界:15n/14,最小的上界(5n+5)/3。

c#代码:

 


usings

namespace CakeSorting
{
    
class Program
    
{
        
private int[] cakeSizeArray;//大饼直径队列
        private int[] cakeArray;//大饼队列
        private Queue<int> cakes;
        
const int cakeNum = 6;
        
private int maxTime = 0;
        
private int minTime = 0;
        
static void Main(string[] args)
        
{
            Program p 
= new Program();
            p.run();
        }


        
void run()
        
{
            init();
            enumeratQueue(cakes.Count());
            Console.ReadLine();
        }


        
void init()
        
{
            
//初始化赋值

            setMaxTime();

            minTime 
= 0;

            cakeArray 
= new int[cakeNum];

            cakeSizeArray 
= new int[cakeNum];

            cakes 
= new Queue<int>();

            
for (int i = 0; i < cakeSizeArray.Length; i++)
            
{
                cakeSizeArray[i] 
= i;
            }
//大饼直径初始化

            
foreach (int i in cakeSizeArray)
            
{
                cakes.Enqueue(i);
            }
//大饼队列化
        }


        
void enumeratQueue(int cn)
        
{
            
if (cn == 1)
            
{
                
int t = cakes.Dequeue();
                cakeArray[
0= t;
                setMaxTime();
                search(
0);
                minTime 
= maxTime > minTime ? maxTime : minTime;
                show();
                cakes.Enqueue(t);
            }


            
for (int i = 0; i < cn; i++)
            
{
                
int t = cakes.Dequeue();
                cakeArray[cn 
- 1= t;
                enumeratQueue(cn 
- 1);
                cakes.Enqueue(t);
            }

        }


        
void search(int step)
        
{
            
if (step > maxTime)
                
return;//大于2(n-1)时退出

            
for (int i = 1; cakeArray [i-1]<cakeArray [i]; i++)
            
{
                
if (i == cakeArray.Length - 1)
                
{
                    maxTime 
= step;
                    
return;
                }

            }
//排序成功退出

            
for (int i = 0; i < cakeArray.Length; i++)
            
{
                revert(
0, i);
                search(step
+1);
                revert(
0, i);
            }
//递归穷举所有方案
        }


        
void revert(int begin, int end)
        
{
            
int t = cakeArray[begin];
            
for (int i = begin, j = end; i < j; i++, j--)
            
{
                t 
= cakeArray[i];
                cakeArray[i] 
= cakeArray[j];
                cakeArray[j] 
= t;
            }

        }


        
void show()
        
{
            
foreach (int i in cakeArray)
            
{
                Console.Write(
"{0}\t", i);
            }

            Console.Write(
"\nMaxTime is:{0}\tMinTime is:{1}\n",maxTime ,minTime);
        }


        
void setMaxTime()
        
{
            maxTime 
= 2 * (cakeNum - 1);
        }

    }

}

 

最优解(已经使用了书中说的当碰到相同状态时根据是否是是更优解的情况判断,程序还可以继续优化,有兴趣的朋友一起讨论):

运行结果: 

 


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CakeArraySorting
{
    
class Program
    
{
        
Main

        
Parameters

        
Process

        
AppendMethods
    }



    
}

 

 

本文转自today4king博客园博客,原文链接:http://www.cnblogs.com/jinzhao/archive/2008/08/22/1274432.html,如需转载请自行联系原作者
相关文章
|
6月前
【Leetcode 2645】构造有效字符串的最小插入数 —— 动态规划
状态定义:`d[i]`为将前 i 个字符拼凑成若干个 abc 所需要的最小插入数。状态转移方程: 如果` word[i]>word[i−1]`,那么`word[i]`可以和`word[i−1]`在同一组 abc 中,`d[i]=d[i−1]−1` ;否则`word[i]`单独存在于一组 abc 中,`d[i]=d[i−1]+2`
|
6月前
|
算法 测试技术 C#
C++二分查找算法:包含每个查询的最小区间
C++二分查找算法:包含每个查询的最小区间
|
6月前
|
算法 测试技术 C++
【位运算 贪心】2835. 使子序列的和等于目标的最少操作次数
【位运算 贪心】2835. 使子序列的和等于目标的最少操作次数
【位运算 贪心】2835. 使子序列的和等于目标的最少操作次数
|
6月前
|
算法 测试技术 C#
【位运算 试填法】【推荐】3022. 给定操作次数内使剩余元素的或值最小
【位运算 试填法】【推荐】3022. 给定操作次数内使剩余元素的或值最小
|
6月前
|
算法 测试技术 C#
【线段树 区间位运算模板】3117划分数组得到最小的值之和
【线段树 区间位运算模板】3117划分数组得到最小的值之和
|
6月前
|
算法 测试技术 C#
【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目
【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目
|
6月前
|
算法 测试技术 C++
【数论】【分类讨论】【C++算法】1611使整数变为 0 的最少操作次数
【数论】【分类讨论】【C++算法】1611使整数变为 0 的最少操作次数
|
6月前
|
算法 测试技术 C++
【动态规划】【C++算法】801. 使序列递增的最小交换次数
【动态规划】【C++算法】801. 使序列递增的最小交换次数
|
6月前
|
存储 算法 Java
给定一个二叉树,请你找出其中最长严格递增路径的长度。(提示:使用动态规划)
给定一个二叉树,请你找出其中最长严格递增路径的长度。(提示:使用动态规划)
40 0
|
11月前
|
算法 测试技术 C#
C++算法:矩阵中的最长递增路径
C++算法:矩阵中的最长递增路径