贪心算法—旅行者过河问题

Posted 云故里

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了贪心算法—旅行者过河问题相关的知识,希望对你有一定的参考价值。

    N位旅行者来了河边。如果不借助船的话,大家是无论如何也不敢过河去的。不幸的是,N个人一共只有一条船,而这条船每次只能坐两个人。如果各自单独划船过河的话,N人所需要的时间已知;而如果两人同时过河,所需要的时间是这两个人各自单独过河所需时间中最慢的时间(比如两个人单独过河所需的时间分别是 2,3,那么如果他们一起过河,所需的时间就是3)。问题是,如何设计一个方案,让这N人尽快过河。

输入:

第一行是一个整数T(1<=T<=20)表示测试数据的组数

每组测试数据的第一行是一个整数N(1<=N<=1000)表示共有N个人要过河

每组测试数据的第二行是N个整数Si,表示此人单独过河所需要花时间。(0<Si<=100)

输出:

输出所有人都过河需要用的最少时间

样例输入:

1

4

1 2 5 10

样例输出:

17



首先,这道题很有意思对吧!,当然也很有难度,它是贪心算法的典型代表,什么?你不知道什么是贪心算法,…. 可以去百度一下,举个例子,让你从10个不一样大小的苹果中选择5个最大的,依次选一个,选5次,你会怎么选?当然每次都选剩下的苹果中最大的一个,对不对,嗯,没错,你每次都很贪心,都选最大的,这样,最终你选的5个苹果就是10个中最大的,好了,这就是贪心算法,实质是: 局部的最优解同时也满足全局的最优解

 

回到题中,求最少时间,分析一下,局部的最优解满不满足全局的最优解,当然满足,每个人过河的时间都最少,所有人花费的时间不就最少了,所以,你要每次都很贪心,每先把最浪费时间的两个人送走,可是怎么送呢? 注意只有一条船,船还是要有人开回来的,所有这就产生了两种方式,

 

注意,以下两种方式是针对4个人及以上的人数时考虑的方法,当人数为3时,只能用第一种方法,因为第二种方法要四个人才能完成,所以循环的条件为 n>2  (0开始的,)

1. 让速度最快的那个人分两次将最费时间的两个人送走,然后它再把船开回来

最快的和最慢的过河,然后最快的将船划回来,再最快的和次慢的过河,然后最快的将船划回来.


          即所需时间为:2*t[0]+t[n-2]+t[n-1]

   

 

2. 最快的和次快的合作,

最快的(即所用时间t[0])和次快的过河,然后最快的将船划回来,再次慢的和最慢的过河,然后次快的将船划回来.

          即所需时间为:t[0]+2*t[1]+t[n-1]

每次都从上面的两种方式中选择时间最小的一种方式,当做送走 最费时间的两个人 所花费的时间,

下面以例子中的数据讲解一下:

 1   2   5  10

初始n=4 ,

排完序后让 n=3

四个人对不对!! 满足循环条件 n>2,所以可以执行循环

1. 考虑第一种方法 t1=0

先让  1 10 过河  花费时间为 10         t1=10

1 把船划回来   花费时间为 1                  t1=10+1=11

1 5 过河          花费时间为  5                  t1=11+5=16

1 把船划回来        花费时间为 1                  t1=16+1=17

此时 5 10都送走了,1 ,2c船都在原处,对不对,

2.考虑第二种方法 t2=0

先让 1 2 过河           花费时间为 2              t2=2

1 划船回来              时间为  1 t2=2+1=3

5 10 划船过河            时间为 10               t2= 3+10=13

2 划船回来               时间为 2                 t2=13+2=15

此时 5 10都送走了,1 ,2c船都在原处,

 

两种方法尝试完毕,此时选择最少的时间  t2=15

此时n=1 ,河这边只剩下 1  2          当然,还有船

一起坐船走吧,时间为 2     所以总时间t= 15+2=17


#include "stdio.h" int main(){ int T,n,i,j,t,a[1001],res=0; int c,min; scanf("%d",&T); while(T--) { scanf("%d",&n); for(i=0;i<n;i++) scanf("%d",&a[i]); /*冒泡排序*/  for(j=0;j<n-1;j++) /*进行9次循环 实现9趟比较*/  for(i=0;i<n-i-1;i++) /*在每一趟中进行9-j次比较*/  if(a[i]>a[i+1])  {  t=a[i];  a[i]=a[i+1];  a[i+1]=t;  }  --n; while(n>2)  { c=a[0]+a[1]*2+a[n]; //看解释 <1>  min=a[0]*2+a[n]+a[n-1]; //看解释 <2>  if(c<min) min=c;  res+=min;//先把最长时间的两个人先送过去  n-=2; } if(n==0) /*只剩下一个人*/ res+=a[0]; else if(n==1) /*剩下两个人,时间按最大的那个人的算*/ res+=a[1]; else /*剩下三个人,最大的和最小的过去,最小的将船划回来,然后带着剩下的那个人过去*/ res+=a[0]+a[1]+a[2]; printf("%d\n",res);  }  return 0;}

分析结束,如果还有什么更好的算法思想,可以在下方留言。 

以上是关于贪心算法—旅行者过河问题的主要内容,如果未能解决你的问题,请参考以下文章

过河问题(贪心算法)

贪心算法——过河问题

贪心算法----过河问题

过河问题 贪心

过河问题-贪心

过河问题