过河问题

来源:互联网 发布:python idle无法运行 编辑:程序博客网 时间:2024/05/17 04:54

一、问题:在漆黑的夜里,N位旅行者来到了一座狭窄而且没有护栏的桥边。如果不借助手电筒的话,大家是无论如何也不敢过桥去的。不幸的是,N个人一共只带了一只手电筒,而桥窄得只够让两个人同时过。如果各自单独过桥的话,N人所需要的时间已知;而如果两人同时过桥,所需要的时间就是走得比较慢的那个人单独行动时所需的时间。问题是,如何设计一个方案,让这N人尽快过桥。


二、分析:

(1)、首先对N个旅行者的过桥时间进行排序,假设排序后的时间是{T1, T2, T3, T4 ... Tn},设N个旅行者过桥的最快时间为sum;

(2)、N = 1,则 sum = T1;N = 2,  sum = max(T1, T2);N = 3, sum = T1+T2+T3 ;

(3)、当N > 3时,考虑最慢和次慢两个人的过桥方法,共有两种方案可选择:

     第一种,最快和次快的人先过去(用时T[1]),然后最快的人回来(用时T[0]),接着最慢和次慢的人过去(用时T[n-1]),最后次快的人回来(用时T[1])。整理后为Tx=T[0] + T[1] + T[1] + T[n-1]=T[0]+2*T[1]+T[n-1]。

     第二种,最快和最慢的过去(用时T[n-1]),然后最快的回来(用时T[0]),接着最快和次慢的人过去(用时T[n-2]),最后次快的人回来(用时T[0])。整理后为Ty=T[0] + T[0] + T[n-1] + T[n-2]=2*T[0]+T[n-1]+T[n-2];(注:这一步很重要,必须两种方案都考虑到,比如这种情况:1,5, 7, 12,当7, 12到对面共花了23,但是如果1带7过去,1 回带12过去,1回,只用了21)

(4)、求取第三步中最慢和次慢过河的最快时间,即:Tmin=max(Tx,Ty);

(5)、此时n-1及n-2这两个旅行者以过河,在递归求解余下的0~n-3这些旅行者即可。


三、编码:

(1)、递归求解:

int Cross(int *T, int n){      if(n == 2)        return T[1];      else if(n == 3)        return T[0] + T[1] + T[2];      else      {          int t1 = T[0] + T[1] + T[1] + T[n-1];        int t2 = T[0] + T[0] + T[n-1] + T[n-2];        return Cross(T, n - 2) + (t1 > t2 ? t2 : t1);      }  }  int RiverProblem(int *T, int n)  {      if(n == 1)        return T[0];         else if(n == 2)        return T[0] > T[1] ? T[0]: T[1];    else    {          sort(T, T + n);        return Cross(T, n);      }}

(2)、非递归求解:

int RiverProblem(int *T, int n)  {      if(n == 1)        return T[0];         else if(n == 2)        return T[0] > T[1] ? T[0]: T[1];      else    {          sort(T, T + n);        int sum = 0;          while(1)          {              if(n == 2)            {                  sum += T[1];                  break;              }              else if(n == 3)            {                  sum += T[0] + T[1] + T[2];                  break;              }              else              {                  int t1 = T[0] + 2 * T[1] + T[n-1];                int t2 = 2 * T[0] + T[n-1] + T[n-2];                sum += (t1 > t2 ? t2 : t1);                  n -= 2;              }          }          return sum;      }  }

(3)、函数指针数组求解:

#include<iostream>#include<algorithm>using namespace std;int (*River[4])(int* T,int n);int River1(int* T,int n){ return T[0];}int River2(int* T,int n){ return T[1];}int River3(int* T,int n){ return T[0]+T[1]+T[2];}int River4(int* T,int n){ int t1 = T[0] + 2 * T[1] + T[n-1];    int t2 = 2 * T[0] + T[n-1] + T[n-2];return River[n-2>3?3:n-2-1](T,n-2)+ (t1 > t2 ? t2 : t1);}int RiverProblem(int* T,int n){sort(T,T+n);return River[n>3?3:n-1](T,n);}int main(){int a[4]={1,5,7,12};River[0]=River1;River[1]=River2;River[2]=River3;River[3]=River4;cout<<RiverProblem(a,4)<<endl;return 0;}


(4)C++模版元编程求解:

#include<iostream>#include<algorithm>using namespace std;template< class TT,int n > struct River{static TT fun(TT* T){static TT sum=0;TT t1 = T[0] + 2 * T[1] + T[n-1];                TT t2 = 2 * T[0] + T[n-1] + T[n-2];sum+=River< TT,n-2 >::fun(T) + (t1 > t2 ? t2 : t1);return sum;}};template< class TT > struct River<TT,3>{static TT fun(TT* T){return T[0]+T[1]+T[2];}};template< class TT > struct River<TT,2>{static TT fun(TT* T){return T[1];}};template< class TT > struct River<TT,1>{static TT fun(TT* T){return T[0];}};int main(){int a[4]={1,5,7,12};sort(a,a+4);cout<<River<int,4>::fun(a)<<endl;return 0;}

(5)C++虚函数实现:

#include<iostream>#include<algorithm>using namespace std;class River{public:virtual int f(int* a,int n){ return -1;}};River* RiverProblem[4];class River1:public River{virtual int f(int* a,int n){ return a[0];}};class River2:public River{virtual int f(int* a,int n){ return a[1];}};class River3:public River{virtual int f(int* a,int n){ return a[0]+a[1]+a[2];}};class River4:public River{virtual int f(int* T,int n){int t1 = T[0] + 2 * T[1] + T[n-1];                int t2 = 2 * T[0] + T[n-1] + T[n-2];int sum=RiverProblem[n-2>3?3:n-2-1]->f(T,n-2) + (t1 > t2 ? t2 : t1);return sum;}};int main(){int a[4]={1,5,7,12};River4 R4; RiverProblem[3]=&R4;River3 R3; RiverProblem[2]=&R3;River2 R2; RiverProblem[1]=&R2;River1 R1; RiverProblem[0]=&R1;sort(a,a+4);cout<<RiverProblem[4>3?3:4-1]->f(a,4)<<endl;return 0;}


(6)汇编实现:

#include<iostream>#include<algorithm>using namespace std;int main(){int a[4]={1,5,7,12},*b=a;int sum;int t1,t2,n=4;sort(a,a+n);__asm{mov edx,n      ;初始化imul edx,4mov ebp,bmov eax,0mov sum,eaxlabel0:cmp edx,0       ;判断je label5cmp edx,4je label1cmp edx,8je label2cmp edx,12je label3mov eax,[ebp]     ;T[0]+2*T[1]+T[n-1]的情况mov ecx,[ebp+4]sal ecx,1add eax,ecxadd eax,[ebp+edx-4]mov t1,eax        mov eax,[ebp]      ;2*T[0]+T[n-1]+T[n-2]的情况sal eax,1add eax,[ebp+edx-4]add eax,[ebp+edx-4*2]mov t2,eaxcmp eax,t1         ;比较选择jg label4mov ecx,sumadd ecx,t2mov sum,ecxmov ecx,2imul ecx,4sub edx,ecxjmp label0label4:mov ecx,sumadd ecx,t1mov sum,ecxmov ecx,2imul ecx,4sub edx,ecxjmp label0label1:                   ;n等于1mov eax,[ebp]add eax,summov sum,eaxjmp label5label2:                    ;n等于2mov eax,[ebp+4]add eax,summov sum,eaxjmp label5label3:                    ;n等于3mov eax,[ebp]add eax,[ebp+4]add eax,[ebp+4*2]add eax,summov sum,eaxlabel5:}cout<<sum<<endl;return 0;}

注意这段汇编代码有问题,运行时会有下面的问题存在:


经过检查是不能使用ebp寄存器,因为ebp和平衡堆栈有关,因此把寄存器ebp改为ebx即可解决问题,正确代码如下:

#include<iostream>#include<algorithm>using namespace std;int main(){int a[4]={1,5,7,12},*b=a;int sum;int t1,t2,n=4;sort(a,a+n);__asm{mov edx,n      ;初始化imul edx,4mov ebx,bmov eax,0mov sum,eaxlabel0:cmp edx,0       ;判断je label5cmp edx,4je label1cmp edx,8je label2cmp edx,12je label3mov eax,[ebx]     ;T[0]+2*T[1]+T[n-1]的情况mov ecx,[ebx+4]sal ecx,1add eax,ecxadd eax,[ebx+edx-4]mov t1,eax        mov eax,[ebx]      ;2*T[0]+T[n-1]+T[n-2]的情况sal eax,1add eax,[ebx+edx-4]add eax,[ebx+edx-4*2]mov t2,eaxcmp eax,t1         ;比较选择jg label4mov ecx,sumadd ecx,t2mov sum,ecxmov ecx,2imul ecx,4sub edx,ecxjmp label0label4:mov ecx,sumadd ecx,t1mov sum,ecxmov ecx,2imul ecx,4sub edx,ecxjmp label0label1:                   ;n等于1mov eax,[ebx]add eax,summov sum,eaxjmp label5label2:                    ;n等于2mov eax,[ebx+4]add eax,summov sum,eaxjmp label5label3:                    ;n等于3mov eax,[ebx]add eax,[ebx+4]add eax,[ebx+4*2]add eax,summov sum,eaxlabel5:}cout<<sum<<endl;return 0;}

0 0
原创粉丝点击