计蒜客 蓝桥杯模拟 快速过河

博客围绕小朋友过河问题展开,介绍了输入格式、输出格式、数据范围和样例解释。重点阐述了动态规划和贪心两种解法,动态规划通过状态转移方程计算前i个人过河的最少时间,贪心则针对不同人数情况给出时间计算方法。
 

在一个夜黑风高的晚上,有 nn 个小朋友在桥的这边,现在他们需要过桥,但是由于桥很窄,每次只允许不超过两人通过,他们只有一个手电筒,所以每次过桥后,需要有人把手电筒带回来,第 ii 号小朋友过桥的时间为 a_iai,两个人过桥的总时间为二者中时间长者。问所有小朋友过桥的总时间最短是多少。

输入格式

第一行输入一个整数 nn,表示有 nn 个小朋友。

第二行有 nn 个整数 a_iai ,a_iai 表示第 ii 个小朋友过河需要的时间。

输出格式

输出一个整数,表示所有小朋友过河所需要的时间。

随后是你的通过和返回次序,每一行是两个或者三个整数,第一个整数,表示这一行有几个整数,后面的一个或者两个整数对应着人(通过时间代表人),返回也要占一行。

数据范围

对于 30\%30% 的数据:1 \le n \le 51n5。

对于 100\%100% 的数据:1 \le n \le 10001n1000 ,0 < a_i \le 10000<ai1000

样例解释

1717 秒

(1,2)(1,222 秒

(1)(111 秒

(5,10)(5,101010 秒

(2)(222 秒

(1,2)(1,222 秒

本题答案不唯一,符合要求的答案均正确

样例输入复制
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;
}

  

转载于:https://www.cnblogs.com/l609929321/p/10563497.html

### 关于2022年蓝桥杯Java比赛中的青蛙过河问题 #### 问题背景 在蓝桥杯竞赛中,“青蛙过河”是一个经典的动态规划或贪心算法类问题。该问题通常涉及算青蛙如何通过一系列石头到达终点,或者最小化某种代价函数。根据已知的参考资料[^1]和[^2],可以推测此问题的核心在于优化路径选择。 --- #### 题目描述(基于引用内容推导) 假设有一条河流,宽度为 `W` 米,起点位于左岸 (位置 0),终点位于右岸 (位置 W)。河中有若干块石子分布在不同位置 `[p_1, p_2, ..., p_n]` 上。每一步,青蛙可以从当前位置跳到任意一块未访问过的石子上,跳跃的距离不得超过其最大跳跃能力 `y`。目标是最少经过多少次跳跃完成整个旅程。 --- #### 解题思路 此类问题可以通过 **动态规划** 来解决: 1. 定义状态: 设 `dp[i]` 表示从起点跳至第 i 块石子所需的最少步数。 2. 初始条件: 如果起始点即为某块石子,则设 `dp[start_index] = 0`;否则初始化所有 dp 数组值为无穷大 (`inf`)。 3. 状态转移方程: 对于当前考虑的每一颗石子 j ,遍历之前已经处理好的 k (k<j),如果满足 abs(p[j]-p[k])<=y 成立的话就尝试更新 dp[j]=min(dp[j], dp[k]+1). 4. 边界情况: 当前石子恰好处于岸边时需特别注意是否可以直接作为有效解的一部分参比较运算之中. 最终答案将是 min{dp[end_stone]} 加上可能存在的额外一次落地动作成本. --- #### 示例代码实现 以下是针对上述逻辑的一种 Python 实现方式: ```python def frog_cross_river(stones, max_jump): import math INF = float('inf') # 初始化 DP 数组 n = len(stones) stones.sort() # 排序方便后续操作 dp = [INF]*n start_pos = 0 end_pos = stones[-1] # 设置初始状态 if stones[0]==start_pos: dp[0]=0 # 动态规划求解过程 for i in range(1,n): currentStone=stones[i] for prevIndex in range(i): previousStone=stones[prevIndex] if abs(currentStone - previousStone)<=max_jump and \ dp[prevIndex]!=INF : dp[i]=min(dp[i], dp[prevIndex]+1) result=min([val for idx,val in enumerate(dp) if stones[idx]==end_pos]) return result if result!=INF else -1 # 测试数据输入部分 if __name__ == "__main__": testStones=[0,1,3,5,7,9,12] jumpCapability=3 answer=frog_cross_river(testStones,jumpCapability) print(f"The minimum number of jumps required is {answer}.") ``` --- #### 注意事项 以上给出的是通用版本解答框架,在实际参赛过程中还需要仔细阅读具体题目细节调整参数定义范围以及边界判定准则等内容。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值