- 武逸程's Note
例——过河问题(动态规划)
- 2023-10-14 21:53:18 @
题目描述
有一个大晴天,Oliver 与同学们一共 人出游,他们走到一条河的东岸边,想要过河到西岸。而东岸边有一条小船。
船太小了,一次只能乘坐两人。每个人都有一个渡河时间 ,船划到对岸的时间等于船上渡河时间较长的人所用时间。
现在已知 个人的渡河时间 ,Oliver 想要你告诉他,他们最少要花费多少时间,才能使所有人都过河。
注意,只有船在东岸(西岸)的人才能坐上船划到对岸。
输入格式
输入文件第一行为人数 ,以下有 行,每行一个数。
第 行的数为第 个人的渡河时间。
输出格式
输出文件仅包含一个数,表示所有人都渡过河的最少渡河时间。
样例 #1
样例输入 #1
4
6
7
10
15
样例输出 #1
42
样例输入 #2
4
1
2
5
10
样例输出 #2
17
提示
数据范围
对于 的数据满足 。
对于 的数据满足 。
题目分析
这道题目很明显不能用贪心算法(虽然每一步都找最优解,但可能结果不是最优解),动态规划才是正解
样例1解释
- 初始:东岸 ,西岸 ;
- 第一次:东岸 ,西岸 ,时间 ;
- 第二次:东岸 ,西岸 ,时间 ;
- 第三次:东岸 ,西岸 ,时间 ;
- 第四次:东岸 ,西岸 时间 ;
- 第五次:东岸 ,西岸 时间 。
所以总时间为 ,没有比这个更优的方案。
样例2解释
- 初始:东岸 ,西岸 ;
- 第一次:东岸 ,西岸 ,时间 ;
- 第二次:东岸 ,西岸 ,时间 ;
- 第三次:东岸 ,西岸 ,时间 ;
- 第四次:东岸 ,西岸 ,时间 ;
- 第五次:东岸 ,西岸 ,时间 ;
所以总时间为 ,没有比这个更优的方案。
大体思路
先把过河时间从小到大排序,然后过河。
过河分为两种情况:
- 岸只剩一个人,让岸最小的来接他
- 岸剩下两个人,让最小的到岸送船,然后原来岸的那两个人(即最大的两个人)到岸,让次小的到岸,最后一起过河
上面看不懂没关系 简单来说就是:
- 让最小的人()来回送其他人():
- 让带着过去,然后回来,再让和过去,最后让去接过去:
从这两种情况中选出用时最短的,列出状态转移方程
状态转移方程
肯定先定义数组啦!
int dp[100005],t[100005];//t存每个人的过河时间
前两个人所花的时间是定值,所以先存到里面去
dp[1]=t[1];
dp[2]=t[2];
然后最最最核心的我不想写,自己去推
咳咳……
dp[i]=min(dp[i-1]+t[1]+t[i],dp[i-2]+t[1]+2*t[2]+t[i]);
最后……没有最后贴上代码
#include<bits/stdc++.h>
using namespace std;
int t[100005],dp[100005];
int main(void){
int n;
cin>>n;
for(int i=1;i<=n;i++) cin>>t[i];
sort(t+1,t+1+n);
dp[1]=t[1];
dp[2]=t[2];
for(int i=3;i<=n;i++)
dp[i]=min(dp[i-1]+t[1]+t[i],dp[i-2]+t[1]+2*t[2]+t[i]);
cout<<dp[n]<<endl;
return 0;
}