过桥问题

来源:互联网 发布:从零开始学习编程 编辑:程序博客网 时间:2024/04/20 12:25

过桥问题:

问题描述:4个人在晚上过一座小桥,过桥时必须要用到手电筒,只有一枚手电筒,每次最多只可以有两人通过, 4个人的过桥速度分别为1分钟、2分钟、5分钟、10分钟,试问最少需要多长时间4人才可以全部通过小桥?

 

Morewindows的方法(以下参考blog: http://blog.csdn.net/MoreWindows/article/details/7481851)

Morewindows君通过观察发现,要么是最快者将最慢的2个送过桥,要么是最快的2个将最慢的2个送过桥即将过桥的人按其过桥的时间从小到大排列,设为AB,…… YZ。其中AB是最快的二个,YZ是最慢的二个。那么就有二种方案:

方案一 最快者将最慢的2个送过桥

第一步:AZ过桥,花费Z分钟。

第二步:A回来,花费A分钟。

第三步:AY过桥,花费Y分钟。

第四步:A回来,花费A分钟。

这四步后总人数就减小2个,花费时间为A + A + Y + Z分钟。

方案二 最快的2个将最慢的2个送过桥

第一步:AB过桥,花费B分钟。

第二步:A回来,花费A分钟。

第三步:YZ过桥,花费Z分钟。

第四步:B回来,花费B分钟。

这四步后总人数同样减小2个,花费时间为A + B + B + Z分钟。

这样,每次比较一下这二种方案就能将总人数减小2。然后我们再考虑一些边界情况:

有三个人过桥设为ABC(已经排好序,下同)。应该花费A + B + C分钟。

有二个人过桥设为AB。那么肯定是花费B分钟。

有一个人过桥设为A。肯定花费A分钟。

上述方法并没有证明其正确性,只不过在实际中可用。

接着自己实现代码如下:

#include<iostream>using namespace std;#define maxn 1001int f1(const void *a,const void *b){    return *(int *)a-*(int *)b;}void f(int *A,int n,int &count){    if(n==3)    {        count+=A[0]+A[1]+A[2];        return ;    }    if(n==2)    {        count+=A[1];        return ;    }    int temp1=2*A[0]+A[n-1]+A[n-2];    int temp2=A[0]+2*A[1]+A[n-1];    count+=temp1>=temp2?temp2:temp1;    n=n-2;    f(A,n,count);    return ;}int main(){    int count;    int N,A[maxn];    while(cin>>N)    {        count=0;        memset(A,0,sizeof(A));        for(int i=0; i<N; i++)            cin>>A[i];        qsort(A,N,sizeof(int),f1);        f(A,N,count);        cout<<count<<endl;    }    return 0;}



3.图论(方法参考:http://blog.csdn.net/drzhouweiming/article/details/1340741

我们把对面的人作为状态节点,来往的时间作为有向路径的权值,用枚举的思想得出如下的图:

问题转化为求空节点到(1,2,5,10)满节点的方法。

 


解决上述问题有两种方法:

1.  Dijkstra单源最短路径。

如果用Dijkstra来解上面的问题,单源最短路径是求源到所有端点的路径,而我们只要求到满节点的路径,故我们会有许多无用的计算。

2.  动态规划。

看出来,上面的图是分阶段了,可以用动态规划。

 

编程实践:

节点数:节点为N的所有子集,有2^N个节点;还得要有退回后的中间节点,我们总共要生成这2^(N+1)个节点。

有向边数:我们只看偶数阶段的节点。每个节点入度为N(N-1)/2的边,即选取两个退回到上一步;出度为N个,即选一个回去。最后每个节点相关N(N+1)/2条边。总共也就是N(N+1)*2^N条边。

 

时间复杂度:

初始化节点和边O(2^(N+1)),O(N^2*2^N);

Dijstra遍历,这时的节点数是2^(N+1),那么即为 O(2^(2N+2));

动态规划遍历,经过所有的边,O(N^2*2^N)。

不管哪种方法,时间复杂度貌似都高的吓人,程序我还是不编了。

 

通过上面的方法,用计算机解决的暂时看来是morewindows君的方法可以实践。

本人水平有限,太菜的地方请高手指正。

 


原创粉丝点击