计蒜客 蓝桥杯模拟 快速过河
在一个夜黑风高的晚上,有 nn 个小朋友在桥的这边,现在他们需要过桥,但是由于桥很窄,每次只允许不超过两人通过,他们只有一个手电筒,所以每次过桥后,需要有人把手电筒带回来,第 ii 号小朋友过桥的时间为 a_iai,两个人过桥的总时间为二者中时间长者。问所有小朋友过桥的总时间最短是多少。
输入格式
第一行输入一个整数 nn,表示有 nn 个小朋友。
第二行有 nn 个整数 a_iai ,a_iai 表示第 ii 个小朋友过河需要的时间。
输出格式
输出一个整数,表示所有小朋友过河所需要的时间。
随后是你的通过和返回次序,每一行是两个或者三个整数,第一个整数,表示这一行有几个整数,后面的一个或者两个整数对应着人(通过时间代表人),返回也要占一行。
数据范围
对于 30\%30% 的数据:1 \le n \le 51≤n≤5。
对于 100\%100% 的数据:1 \le n \le 10001≤n≤1000 ,0 < a_i \le 10000<ai≤1000
样例解释
1717 秒
(1,2)(1,2) 22 秒
(1)(1) 11 秒
(5,10)(5,10) 1010 秒
(2)(2) 22 秒
(1,2)(1,2) 22 秒
样例输入
4 1 2 5 10
样例输出
17 2 1 2 1 1 2 5 10 1 2 2 1 2
题解:
动态规划:
我们先将所有人按花费时间递增进行排序,假设前 i 个人过河花费的最少时间为 opt[i],那
么考虑前i-1个人已经过河的情况,即河这边还有1个人,河那边有i-1个人,并且这
时候手电筒肯定在对岸,所以 opt[i] = opt[i-1] + a[1] + a[i] (让花费时间最少的人把手
电筒送过来,然后和第i个人一起过河) 。
如果河这边还有两个人,一个是第i号,另外一个无关,河那边有i-2个人,并且手电筒
肯定在对岸,所以 opt[i] = opt[i-2] + a[1] + a[i] + 2*a[2](让花费时间最少的人把
电筒送过来,然后第i个人和另外一个人一起过河,由于花费时间最少的人在这边,所以下
一次送手电筒过来的一定是花费次少的,送过来后花费最少的和花费次少的一起过河,解决
问题),所以 opt[i] = min(opt[i-1]+a[1]+a[i],opt[i-2]+a[1]+a[i]+2*a[2])
贪心:
一个人:时间为a0 。
两个人:时间为a1。
三个人:时间为a0+a1+a2 。
多个人:比较下面两种方案中的最优值。
a[0]*2+a[n]+a[n-1] ? a[0]+2*a[1]+a[n]
#include <map> #include <set> #include <stack> #include <cmath> #include <queue> #include <cstdio> #include <vector> #include <string> #include <bitset> #include <cstring> #include <iomanip> #include <iostream> #include <algorithm> #define ls (r<<1) #define rs (r<<1|1) #define debug(a) cout << #a << " " << a << endl using namespace std; typedef long long ll; const ll maxn = 1e5+10; const ll mod = 1e9+7; const double pi = acos(-1.0); const double eps = 1e-8; ll n, sum = 0, a[maxn], dp[maxn]; int main() { scanf("%lld",&n); for( ll i = 0; i < n; i ++ ) { scanf("%lld",&a[i]); } sort(a,a+n); dp[0] = a[0]; dp[1] = a[1]; for( ll i = 2; i < n; i ++ ) { dp[i] = min( dp[i-1]+a[0]+a[i], dp[i-2]+a[0]+2*a[1]+a[i] ); } printf("%lld\n",dp[n-1]); n --; while( 1 ) { if( !n ) { sum += a[0]; printf("1 %lld\n",a[0]); break; } else if( n == 1 ) { sum += a[1]; printf("2 %lld %lld\n",a[0],a[1]); break; } else if( n == 2 ) { sum += a[0] + a[1] + a[2]; printf("2 %lld %lld\n",a[0],a[1]); printf("1 %lld\n",a[0]); printf("2 %lld %lld\n",a[0],a[2]); break; } else { if( a[0]*2+a[n]+a[n-1]>a[0]+2*a[1]+a[n] ) { sum += a[0]+2*a[1]+a[n]; printf("2 %lld %lld\n",a[0],a[1]); printf("1 %lld\n",a[0]); printf("2 %lld %lld\n",a[n-1],a[n]); printf("1 %lld\n",a[1]); n -= 2; } else { sum += a[0] + a[n]; printf("2 %lld %lld\n",a[0],a[n]); printf("1 %lld\n",a[0]); n -= 1; } } } return 0; }