zoukankan      html  css  js  c++  java
  • 经典数学问题<手电过河问题>的动态解法--问题规模扩展至任意大小

    非常有趣的一件事是今天在TopCoder的1000分题里面发现了这道经典数学问题。                                                                                                                         

                                                                                                                                                                                                                                                                 

             

                Notes          

           
              -                   In an optimal solution, exactly two people will be sent across the           bridge with the flashlight each time (if possible), and exactly one           person will be sent back with the flashlight each time. In other           words, in an optimal solution, you will never send more than one           person back from the far side at a time, and you will never send           less than two people across to the far side each time (when           possible).        
             

                Constraints          

           
              -                   times will have between 1 and 6 elements, inclusive.        
              -                   Each element of times will be between 1 and 100, inclusive.        
             

                Examples          

           
              0)                          
                                                                                                                                                                
                                                                                           
                         
    { 1, 2, 5, 10 }
                       
                 
                   
    Returns: 17
                 
                                                                                           
                          The example from the text.                    
                 
           
              1)                          
                                                                                                                                                                
                                                                                           
                         
    { 1, 2, 3, 4, 5 }
                       
                 
                   
    Returns: 16
                 
                                                                                           
                          One solution is: 1 and 2 cross together (2min), 1 goes                       back (1min), 4 and 5 cross together (5min), 2 goes back                       (2min), 1 and 3 cross together (3min), 1 goes back                       (1min), 1 and 2 cross together (2min). This yields a                       total of 2 + 1 + 5 + 2 + 3 + 1 + 2 = 16 minutes spent.                    
                 
           
              2)                          
                                                                                                                                                                
                                                                                           
                         
    { 100 }
                       
                 
                   
    Returns: 100
                 
                                                                                           
                          Only one person crosses the bridge once.                    
                 
           
              3)                          
                                                                                                                                                                
                                                                                           
                         
    { 1, 2, 3, 50, 99, 100 }
                       
                 
                   
    Returns: 162
                 
                                 
           

       

    计算的这道题方法其实类似于动态规划,关键在于寻找最优子结构

    1)问题的最优子结构是这样推出的

      1.每一个人都得过河

      2.由1可以知道cost最大的一个也必须过河

      3.由2可知必然有一次过河的代价为cost(max)

      4.由3可知,在将cost最大的人送过河的运输中最优的方案是将cost第二大的人也同时过河

      因此问题可以转化为如何将cost第一大和第二大的两个人同时送过河

    2)最优化问题的解法在于首先将cost最小的两个人先送过河然后选择其一送回手电筒(无论哪个人都一样),然后再使cost最大和第二大的两个人同时过河,再另上一次剩在另一  岸的cost最小或者次小的人送回手电筒

      因此每次将一对人送过河的cost=iMax1st+(iMin2nd+2*iMin1st)

    3)按总人数的奇数偶数可以将整个问题循环之后分支为两个子问题(显而易见,不多赘述)

    4)利用大根堆和小根堆使遍历的时间复杂度从n降低至logn

    多次实验后代码如下(以下大部分是大根堆小根堆的搭建代码):

      1 #include<set>
      2 #include<vector>
      3 #include<set>
      4 #include<vector>
      5 #include<iostream>
      6 
      7 using namespace std;
      8 
      9 #define HEAP_SIZE 1024
     10 //////////////////////////////////////////
     11 template<typename T>
     12 class MaxHeap{
     13     T*arrData;
     14     int top;
     15     ////////////Filters Up&Down
     16 
     17     void swap(T*l,T*r){
     18         T temp=*l;
     19         *l=*r;
     20         *r=temp;
     21     }
     22 
     23 //////////////////////////////////////////
     24     void FilterUp(){
     25         int kid=top-1;
     26         int parent=(kid-1)/2;
     27         while(arrData[kid]>arrData[parent]){
     28             swap(&arrData[kid],&arrData[parent]);
     29             kid=parent;
     30             parent=(parent-1)/2;
     31         }
     32     }
     33 /////////////////////////////////////////
     34     void FilterDown(){
     35         int parent=0;
     36         int kid=arrData[parent*2+1]>arrData[parent*2+2]?parent*2+1:parent*2+2;
     37         while(kid<top&&arrData[kid]>arrData[parent]){
     38             swap(&arrData[kid],&arrData[parent]);
     39             parent=kid;
     40             kid=arrData[parent*2+1]>arrData[parent*2+2]?parent*2+1:parent*2+2;
     41         }
     42     }
     43 public:
     44     MaxHeap():top(0){ arrData=new T[HEAP_SIZE]; }
     45     ~MaxHeap(){ delete arrData; }
     46 
     47 /////////////////////////////////////////////
     48 ////// Constractor & Destructor Above
     49 /////////////////////////////////////////////
     50     bool insert(T v){
     51         if(top<HEAP_SIZE){
     52             arrData[top]=v;
     53             top++;
     54             FilterUp();
     55             return true;
     56         }else return false;
     57     }
     58 
     59     T remove(){
     60         if(top){
     61             int iTop=arrData[0];
     62             arrData[0]=arrData[top-1];
     63             top--;
     64             FilterDown();
     65             return iTop;
     66         }else return 0;
     67     }
     68 };
     69 
     70 //////////////////////////////////
     71 template<typename T>
     72 class MinHeap{
     73     T*arrData;
     74     int top;
     75     ////////////Filters Up&Down
     76 
     77     void swap(T*l,T*r){
     78         T temp=*l;
     79         *l=*r;
     80         *r=temp;
     81     }
     82 
     83 //////////////////////////////////////////
     84     void FilterUp(){
     85         int kid=top-1;
     86         int parent=(kid-1)/2;
     87         while(arrData[kid]<arrData[parent]){
     88             swap(&arrData[kid],&arrData[parent]);
     89             kid=parent;
     90             parent=(parent-1)/2;
     91         }
     92     }
     93 /////////////////////////////////////////
     94     void FilterDown(){
     95         int parent=0;
     96         int kid=arrData[parent*2+1]<arrData[parent*2+2]?parent*2+1:parent*2+2;
     97         while(kid<top&&arrData[kid]<arrData[parent]){
     98             swap(&arrData[kid],&arrData[parent]);
     99             parent=kid;
    100             kid=arrData[parent*2+1]<arrData[parent*2+2]?parent*2+1:parent*2+2;
    101         }
    102     }
    103     //////////////////////////////////////////////////////
    104 public:
    105     MinHeap():top(0){ arrData=new T[HEAP_SIZE]; }
    106     ~MinHeap(){ delete arrData; }
    107 
    108 /////////////////////////////////////////////
    109 ////// Constractor & Destructor Above
    110 /////////////////////////////////////////////
    111     
    112     bool insert(T v){
    113         if(top<HEAP_SIZE){
    114             arrData[top]=v;
    115             top++;
    116             FilterUp();
    117             return true;
    118         }else return false;
    119     }
    120 
    121     T remove(){
    122         if(top){
    123             int iTop=arrData[0];
    124             arrData[0]=arrData[top-1];
    125             top--;
    126             FilterDown();
    127             return iTop;
    128         }else return 0;
    129     }
    130 };
    131 
    132 class BridgeCrossing{
    133     
    134     void init(vector<int> v){
    135         for(int i=0;i<v.size();i++){
    136             here.insert(v[i]);
    137             here2.insert(v[i]);
    138         }
    139     }
    140 
    141 public:
    142     MinHeap<int> here;
    143     MinHeap<int> there;
    144     MaxHeap<int> here2;
    145     int minTime(vector<int> times){
    146         int iTotal=0;
    147         init(times);
    148         int max1st=-1;
    149         int    max2nd=-1;
    150         int min1st=here.remove();
    151         int min2nd=here.remove();
    152         //////Returning Back
    153         there.insert(min1st);
    154         here.insert(min2nd);
    155         while(true){
    156             max1st=here2.remove();
    157             if(max1st==min2nd)break;
    158             max2nd=here2.remove();
    159             if(max2nd==min2nd)break;
    160             iTotal+=max1st+min1st+2*min2nd;
    161         }
    162         if(max1st==min2nd){
    163             iTotal+=min2nd;
    164             return iTotal;
    165         }else if(max2nd==min2nd){
    166             iTotal+=min2nd+min1st+max1st;
    167             return iTotal;
    168         }else return -1;
    169     }
    170 };
  • 相关阅读:
    PHP: 深入pack/unpack
    gitlab add sshkey(包括第二个key)
    mysql insert与replace 性能
    python3 构造数据
    python 中matplotlib 绘图
    Anaconda安装方法
    永久解决IDEA 连接 mysql时区问题`
    输入3个字符串,按从小到大的顺序输出。要求使用指针的方法进行处理。
    给定字符串定义char *a = “I love China!”,读入整数n,输出在进行了a = a + n这个赋值操作以后字符指针a对应的字符串
    输入a、b、c三个整数,按先大后小的顺序输出a、b和c。注意请使用指针变量的方式进行比较和输出。
  • 原文地址:https://www.cnblogs.com/guguli/p/4357922.html
Copyright © 2011-2022 走看看