POI2004[MOS] 贪心+DP

Posted saionjisekai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POI2004[MOS] 贪心+DP相关的知识,希望对你有一定的参考价值。

---恢复内容开始---

描述

一个夜晚一些旅行者想要过桥. 他们只有一个火把. 火把的亮光最多允许两个旅行者同时过桥. 没有火把或者多于2个人则不能过桥.每个旅行者过桥都需要特定的时间,

两个旅行者同时过桥时时间应该算较慢的那个. 我们想知道所有旅行者最少要花费多少时间才能全部过桥?

 

Example 假如有4个人. 他们分别需要花费6,7,10,15分钟过桥.下图演示了他们如何使用44分钟全部过桥的,但他们能做得更快么?(没有图)

输入

第一行一个数n 表示旅行者的总数, 1 <= n <= 100,000. 接下来n 行表示所有旅行者的过桥时间,时间从小到大排列,每个数不超过1,000,000,000.

输出

输出一个数表示最少过桥时间.

样例输入[复制]
4
6
7
10
15
样例输出[复制]
42
 
 
这道题目好像是相当的神奇,因为我一看到以为是结论题,就是直接第一个人一直跑就行了
结果这么写直接爆0,5555QAQ
这道题有两个最优的方法
1.同我上面那里说的一样,最快的人(第一个)和最慢的人先过去,然后最快的人再回来
2.第二种比较奇葩,第1个人和第2个人过桥,然后1送回火把,让最慢的人和次慢的人过桥,再让2号回来
第一种只能运送1个人,第二种一次能送2个人
我理性分析了一下,强行解释一下:
这道题因为一次限制2个人过去,第一种方法的设计就是尽快让最慢的1个人过去,而第二种因为最慢和次慢同时过去可以比分开过节省一个次慢的时间,这是最重要的,至于为什么用12号来回跑不用说了
为什么一次不送三个人?因为我们一次只能走两个人,利用两个人最慢优化次慢的那个,如果一次过多个人这题tm还能这么简单代码的做?
 
到这里你会发现我一直在谈论如何过最慢的问题,那么这玩意的dp顺序就是按最慢的来,也就是倒着来(相比较肯定先走慢的容易省更多的时间)
 
设 f[i] 是从第n个人开始从后往前送,送到了第 i 个人这里了的最短时间
 
对于第一种情况,到这里花费的总时间肯定是 a[1]+a[i]+f[i+1]
 
第二种情况到这里花费的总时间肯定是 a[i+1]+a[1]+2*a[2]+f[i+2]
对这个方程做一些解释,a[i+1] 是 i 与 i+1 人一起走花费 a[i+1] 的时间,1号返回一次记一次a[1],12号一起过去花费a[2] , 2号回来花费a[2]时间,总共2倍,f[i+2]也就简单了
 
代码竟然出人意料的短,输入竟然是有序的233
code:
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<algorithm>
 4 using namespace std;
 5 long long a[1000005],f[1000005];
 6 int main(){
 7 //    freopen("2072.in","r",stdin);
 8 //    freopen("2072.out","w",stdout);
 9     long long n;cin>>n;
10     long long sum=0;
11     for(long long i=1;i<=n;i++)
12         cin>>a[i];
13     if(n<=2){
14         cout<<a[n];
15         return 0;
16     }
17     f[n]=a[n]+a[1];
18     for(int i=n-1;i>=1;i--)
19         f[i]=min(a[i]+a[1]+f[i+1],a[i+1]+2*a[2]+a[1]+f[i+2]);
20     cout<<f[3]+a[2];
21     return 0;
22 } 

overQAQ

以上是关于POI2004[MOS] 贪心+DP的主要内容,如果未能解决你的问题,请参考以下文章

bzoj 2067 [Poi2004]SZN——二分+贪心

[POI2004] SZP (贪心+拓扑排序)

BZOJ 2073: [POI2004]PRZ [DP 状压]

BZOJ_2068_[Poi2004]SZP_树形DP

bzoj1124[POI2008]枪战maf tarjan+树规+贪心/线性DP

[bzoj3037/2068]创世纪[Poi2004]SZP_树形dp_并查集_基环树