过河问题
来源:互联网 发布: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;}
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- 过河问题
- ffmpeg代码笔记1:获取MP4文件的时长
- 版本控制Android Studio不需要上传的文件
- Stanford Parser demo错误:Unsupported major.minor version 52.0 error
- 【C/C++学院】(5)面向对象编程练习--h和cpp分开编写
- 管理应用的内存
- 过河问题
- 技术人员的未来:做技术还是做管理?
- WIN32 API WNDCLASSEX style ->
- 电子传真在金融业务的应用
- Python机器学习库
- 为 httpclient 设置代理, 设置http头.
- Android性能优化典范
- ibtaits动态列查询显示
- 【转】c#重写一个TabControl