今天在群里面看到有人在讨论关于过河的最优解的问题。开始由于理解的错误,我做得完全错误,后面百度后,此问题的具体描述如下:
有N个人想要用一条每次只能坐两人的船过河,因此,需要合理的安排来、回以使所有的人都能顺利过河。每个人过河的速度不同,两个人速度取决于速度较慢的一个。你的任务就是想一个策略让所有的人在最短的时间内均过河。
要求 :时间限制:1000MS 内存限制:10000KB
通过次数(Accepted):3 提交次数(Submit):24
说明:
输入
第一行是一个表示测试用例次数的整数T(1<=T<=20),接下来是T个测试用例。每个测试用例的第一行是一个整数N,第二行包含N个整数代表每个人过河的时间。不会超过1000个人(即N<=1000)并且每个人的过河时间不会超过100秒。
输出
每一个测试用例,输出N个人过河所用的最短总时间。
输入示例
1
4
1 5 2 10
输出示例
17
//算法
1.正确的算法:
如果n=3, 过河时间为A+B+C
如果n<=2, 好算, 不费口舌了
如果n>=4, 这个是重点:
每次优先考虑把最慢两人送过河
把n人中最快两人记为A,B, 最慢两人记为C,D(过河时间A<B<C<D), n人问题实质上转换为4人过河问题, 参考到4人过河时的优化,
记AB过河, A回, CD过河, B回, 为方法X, 实质是利用最快两人进行优化, 耗时A+2B+D
记AD过河, A回, AC过河, A回, 为方法y, 实质是利用最快一人来过河, 耗时2A+C+D
每次比较这两个方法, 如果x快, 使用x方法, 如果y快, 则用y, 并且, 一旦某次使用y方法后, 以后都不用比较了, 全部使用y方法过河
2.算法正确性证明:
为什么每次先让最慢两人过河? 因为他们迟早要过河...早过晚过一样, 而晚过的话, 有可能时间不能被优化, 所以选择最先过
为什么是两人, 不是三人? 因为这船一次只能两人, 三人问题和两人问题的优化一样, 所以一次考虑三人毫无意义, 同理, 三人以上不加考虑
为什么某次用y过河后不用再比较xy了?
先看这个例子:
1 99 100 101
用x方法是99+1+101+99= 300
y方法是 101+1+100+1 = 203
y比x快的原因是2A+C+D < A+2B+D, 即 A+C<2B
容易想到, 从此以后A+C都会小于2B了(因为C越来越小)
3.code
#include<iostream>
#include<algorithm>
using namespace std;
int a[1001];
int main()
{
int t,i,n,fast1,fast2,slow1,slow2,slow3,sum,l,r;
cin>>t;
while(t--)
{
sum=0;
cin>>n;
for(i=1;i<=n;i++)
cin>>a[i];
sort(a+1,a+n+1);
fast1=a[1];fast2=a[2];slow1=a[n-1];slow2=a[n];slow3=0;
l=1;r=n;
while(n!=0)
{
if(n==1) {sum+=slow2;break;}
if(n==2) {sum+=slow2;break;}
if(n==3) {sum+=(slow2+slow1+fast1);break;}
if(2*fast2>=fast1+slow1) {sum+=(slow1+slow2+2*fast1);r-=2;slow2=a[r];slow1=a[r-1];n-=2;}
else {sum+=2*fast2+fast1+slow2;r-=2;slow2=a[r];slow1=a[r-1];n-=2;}
}
cout<<sum<<endl;
}
return 0;
}
摘自:http://hi.baidu.com/kk0602/blog/item/e9cadb1e1212fdf3e0fe0b03.html
总结:
1. 此问题描述的实际就是采用最好的去优化最差的,实现整体最优的平均化
2. 此种思想首先让我想到的却是尊老爱幼,呵呵,因为活动能力最强的是青年。老年幼年都是需要呵护的对象。只有尊老爱幼才会实现社会的整体繁荣,也就是1中提到的平均最优
3. 根据这种思想,其实也算是求带权图的最优便利方法,因此,按理来说,带权图也有最优遍历解法,这个我暂时不清楚,需要继续学习
这样的话,上面问题的求解,其实就转换成了:一个无向有权图,找一条路径,使之遍历所有节点,要求权值之和最小。
4. 听说在5人的时候,最优解是28秒,而不是29秒,这个,我无解。。,但是根据29秒算法