任意次序的n个烙饼最小反转次数求解 暑期学习笔记(十)

 贴上详细的题目:

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

 

ContractedBlock.gifExpandedBlockStart.gifCode
ContractedBlock.gifExpandedBlockStart.gifusings#region usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Generic;
#endregion


namespace CakeSorting
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
Vars#region Vars
        
private int[] cakeSizeArray;//大饼直径队列
        private int[] cakeArray;//大饼队列
        private Stack<int> steps;
        
private Queue<int> cakes;
        
const int cakeNum = 7;
        
private int maxTime = 0;
        
private int minTime = 0;
        
#endregion


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


        
void run()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            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()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//初始化赋值

            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++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                cakeSizeArray[i] 
= i;
            }
//大饼直径初始化

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


        
void enumeratQueue(int cn)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (cn == 1)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
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++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
int t = cakes.Dequeue();
                cakeArray[cn 
- 1= t;
                enumeratQueue(cn 
- 1);
                cakes.Enqueue(t);
            }

        }


        
void search(int step)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
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++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (i == cakeArray.Length - 1)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    maxTime 
= step;
                    
return;
                }

            }
//排序成功退出

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


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

        }


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

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


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


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

            
return count;
        }

    }

}

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

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

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

c#代码:

 

ContractedBlock.gifExpandedBlockStart.gifCode
ContractedBlock.gifExpandedBlockStart.gifusings#region usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.Generic;
#endregion

namespace CakeSorting
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
        
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)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Program p 
= new Program();
            p.run();
        }


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


        
void init()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//初始化赋值

            setMaxTime();

            minTime 
= 0;

            cakeArray 
= new int[cakeNum];

            cakeSizeArray 
= new int[cakeNum];

            cakes 
= new Queue<int>();

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

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


        
void enumeratQueue(int cn)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (cn == 1)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
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++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
int t = cakes.Dequeue();
                cakeArray[cn 
- 1= t;
                enumeratQueue(cn 
- 1);
                cakes.Enqueue(t);
            }

        }


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

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

            }
//排序成功退出

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


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

        }


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

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


        
void setMaxTime()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            maxTime 
= 2 * (cakeNum - 1);
        }

    }

}

 

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

运行结果:

 

ContractedBlock.gifExpandedBlockStart.gifCode
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace CakeArraySorting
ExpandedBlockStart.gifContractedBlock.gif
{
    
class Program
ExpandedSubBlockStart.gifContractedSubBlock.gif    
{
ContractedSubBlock.gifExpandedSubBlockStart.gif        
Main#region Main

        
static void Main(string[] args)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            Program p 
= new Program();
            p.run();
            Console.ReadLine();
        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
Parameters#region Parameters
        
        
private int[] cakeSizeArray;//大饼直径队列

        
private int[] cakeArray;//大饼队列

        
private int[] maxCakeArray;

        
private Queue<int> cakes;

        
const int cakeNum = 9;

        
private int maxTime = 0;

        
private int minTime = 0;

        
private int lowwerTime;

        
private int ID = 0;

        
private int[] timeTable;

        
private DateTime startTime;

        
private TimeSpan ts;

        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
Process#region Process

        
void run()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            init();
            enumeratQueue(cakes.Count());
            ts 
= DateTime.Now - startTime;

            Console.Write(
"MaxCakeArray:\t");
            
foreach (int i in maxCakeArray)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                Console.Write(
"{0}\t", i);
            }

            Console.WriteLine(
"\nCost Time:{0}\t MaxTime:{1}", ts, minTime);
        }


        
void init()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//初始化赋值
            startTime = DateTime.Now;

            setMaxTime();

            lowwerTime 
= (int)15 * cakeNum / 14;

            minTime 
= 0;

            cakeArray 
= new int[cakeNum];

            cakeSizeArray 
= new int[cakeNum];

            maxCakeArray 
= new int[cakeNum];

            cakes 
= new Queue<int>(cakeNum);

            setCakes();

            cakesEnqueue();

            timeTable 
= new int[getFactorial(cakeNum)];

        }


        
#endregion


ContractedSubBlock.gifExpandedSubBlockStart.gif        
AppendMethods#region AppendMethods

        
void enumeratQueue(int cn)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
if (cn == 1)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
int t = cakes.Dequeue();
                cakeArray[
0= t;
                setMaxTime();
                Console.Write(
"ID:{0}", ID);
                
//foreach (int i in cakeArray)
                
//{
                
//    Console.Write("\t{0}", i);
                
//}
                if (getNeberNum() == cakeNum - 1)//无相邻直径大小的饼
ExpandedSubBlockStart.gifContractedSubBlock.gif
                {
                    setTimeTable();
                    search(
0);
                    minTime 
= maxTime > minTime ? maxTime : minTime;
                    
if (minTime == maxTime)
                        Array.Copy(cakeArray, maxCakeArray, cakeNum);
                    
//show();
                }

                
else
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    Console.WriteLine(
"jump!.");
                }

                ID
++;
                cakes.Enqueue(t);
            }


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

        }


        
void search(int step)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//if (cakeNum == 1)
            
//    return;

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

            
if (step + getNeberNum() > maxTime)
                
return;

            
int p = getID();
            
if (step <= timeTable[p])
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                timeTable[p] 
= step;
            }

            
else
                
return;

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

            }
//排序成功退出

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


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

        }


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


        
void setCakes()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
for (int i = 0; i < cakeSizeArray.Length; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                cakeSizeArray[i] 
= i;
            }
//大饼直径初始化,简便期间直接用相邻数字
        }


        
void cakesEnqueue()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
foreach (int i in cakeSizeArray)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                cakes.Enqueue(i);
            }
//大饼队列化
        }


        
void setMaxTime()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
//maxTime = 2 * (cakeNum - 1);
            maxTime = (5 * cakeNum + 5/ 3;
        }


        
int getNeberNum()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
int ret = 0;
            
for (int i = 1; i < cakeNum;i++ )
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (Math.Abs(cakeArray[i - 1- cakeArray[i]) != 1)
ExpandedSubBlockStart.gifContractedSubBlock.gif                
{
                    ret
++;
                }

            }

            
return ret;
        }


        
int getMaxLowwerNum()//计算15n/14~=n的最大数,计算得为14
ExpandedSubBlockStart.gifContractedSubBlock.gif
        {
            
int i = 1;
            
for (; 15 * i / 14 - i < 1; i++) ;
                
return i;
        }


        
int getFactorial(int n)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
int ret;
            
for (ret = n; n > 1; n--)
                ret 
*= n - 1;
            
return ret;
        }


        
int getID( )
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
int ret = 0;
            
for (int i = 0; i < cakeArray.Length; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                ret 
+= getNumSize(i) * getFactorial(cakeNum - i - 1);
            }

            
return ret;
        }


        
int getNumSize(int p)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
int ret=0;
            
for (int i = p + 1; i < cakeArray.Length; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                
if (cakeArray[p] < cakeArray[i])
                    ret
++;
            }

            
return ret;
        }


        
void setTimeTable()
ExpandedSubBlockStart.gifContractedSubBlock.gif        
{
            
for (int i = 0; i < timeTable.Length; i++)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
{
                timeTable[i] 
= (int)(5 * cakeNum + 5/ 3;
            }

        }


        
#endregion

    }



    
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值