小朋友过桥问题:
在一个夜黑风高的晚上,有n(n <= 50)个小朋友在桥的这边,现在他们需要过桥,但是由于桥很窄,每次只允许不大于两人通过,他们只有一个手电筒,所以每次过桥的两个人需要把手电筒带回来,i号小朋友过桥的时间为T[i],两个人过桥的总时间为二者中时间长者。问所有小朋友过桥的总时间最短是多少。
问题分析:
先将小朋友过河的时间从小到大排序
当一个小朋友过河时:时间sum=T[1];
当两个小朋友过河时:时间sum=T[2];
当三个小朋友过河时:时间sum=T[2]+T[1]+T[3];
/*
第一步小朋友1和小朋友2过河,时间为T[2];小朋友1回来,时间为T[1],小朋友1和小朋友3过河时间为T[3].
*/
当第四个小朋友过河时则会出现不同的情况:
一:小朋友1和小朋友2过河,时间为T[2];小朋友1回来,时间为T[1],小朋友1和小朋友3过河,时间为T[3];小朋友1回来,时间为T[1];小朋友1和小朋友4过河,时间为T[4]。
总时间为:2*T[1]+T[2]+T[3]+T[4];
二:小朋友1和小朋友2过河,时间为T[2];小朋友1回来,时间为T[1],小朋友3和小朋友4过河,时间为T[4],小朋友[2]回来,时间为T[2],再小朋友1和小朋友2过河时间为T[2]。
总时间为:T[1]+3*T[2]+T[4]
同理,当n个小朋友过河时也需要考虑这种情况:
/*
在这道题中我们可以用递归算法来思考,我在已经有n-2个小朋友过河的情况下,让小朋友1回来时,是让小朋友1继续带一个小朋友回去,还是让剩下的两个小朋友回去,再让小朋友2来接小朋友1呢?
*/
当n个小朋友过河时,设f(n-2)为前n-2个小朋友所花的时间
则第一种情况的时间为:f(n-2)+T[1]+T[n]+T[2]+T[2]
第二种情况的时间为:f(n-2)+T[1]+T[n-1]+T[1]+T[n]
如此我们只需要加入条件 当T[1]+T[n-1]>2*T[2]时进入第一种情况,反之则进入第二种情况
实现代码如下:
#include<stdio.h>
int AcrossRiver(int a[],int n);
int main(){
int n;
scanf("%d",&n);
int a[n+1];
int num=0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
}
for(int i=1;i<=n;i++){//时间排序,从小到大
for(int j=n;j>i;j--){
if(a[i]>a[j]){
num=a[j];
a[j]=a[i];
a[i]=num;
}
}
}
printf("%d",AcrossRiver(a,n));
return 0;
}
int AcrossRiver(int a[],int n){
if(n<=2){
return a[n];
}
if(n==3){
return a[2]+a[1]+a[3];
}
int f_n2 = a[2];
int f_n1 = a[1]+a[2]+a[3];
int f_n = 0;
for(int i = 4; i <= n; ++i)
{
if(a[1]+a[n-1]>=2*a[2]){
f_n = a[1] + 2*a[2] + a[i] + f_n2;
f_n2 = f_n1;
f_n1 = f_n;
}else{
f_n=2*a[1]+a[n]+a[n-1]+f_n2;
f_n2 = f_n1;
f_n1 = f_n;
}
}
return f_n;
}