0/1背包变化

题目:poj1837

题意:有一个天平,天平左右两边各有若干个钩子,总共有C个钩子,有G个钩码,求将钩码全部挂到钩子上使天平平衡的方法的总数。其中可以把天枰看做一个以x轴0点作为平衡点的横轴。

解答:dp[i][j]表示放入前i个钩码平衡度为j的种数。因为数组下标不能为负数所以把-7500到7500平移到0到15000.状态转移方程见下表。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int dp[25][15005];
int main()
{
    int c,g,a[25],b[25];
    scanf("%d%d",&c,&g);
    for(int i = 1;i <= c;i++)
        scanf("%d",&a[i]);
    for(int i = 1;i <= g;i++)
        scanf("%d",&b[i]);
    dp[0][7500] = 1;
    for(int i = 1;i <= g;i++)
        for(int j = 0;j <= 15000;j++)///!!!
        if(dp[i-1][j])
        for(int k = 1;k <= c;k++)
        dp[i][j+a[k]*b[i]] += dp[i-1][j];//因为dp[i][j+a[k]*b[i]]的上一个状态只有一种:dp[i-1][j](每个钩码必须使用),且左边状态之前可能已经有了
    printf("%d\n",dp[g][7500]);
    return 0;
}


### 0/1背包问题的多种算法求解方法及其比较 #### 动态规划法 动态规划是一种常用的解决0/1背包问题的方法。其核心思想是通过构建一个二维数组 `dp[i][j]` 来表示从前 `i` 个物品中选择,当背包容量为 `j` 时的最大价值。状态转移方程如下: \[ dp[i][j] = \max(dp[i-1][j], dp[i-1][j-w_i]+v_i) \] 其中 \( w_i \) 和 \( v_i \) 分别代表第 \( i \) 个物品的重量和价值[^5]。 这种方法的时间复杂度为 \( O(nC) \),空间复杂度也可以优化至 \( O(C) \)[^5]。 ```python def knapsack_dp(weights, values, capacity): n = len(values) dp = [[0]*(capacity+1) for _ in range(n+1)] for i in range(1, n+1): for j in range(capacity+1): if weights[i-1] <= j: dp[i][j] = max(dp[i-1][j], dp[i-1][j-weights[i-1]] + values[i-1]) else: dp[i][j] = dp[i-1][j] return dp[n][capacity] ``` --- #### 蛮力法 蛮力法通过对所有可能的物品组合进行穷举来找到最优解。对于有 \( n \) 个物品的情况,共有 \( 2^n \) 种可能性。虽然该方法简单易懂,但由于指数级时间复杂度 \( O(2^n) \),仅适用于小规模问题[^1]。 ```python from itertools import combinations def knapsack_brute_force(weights, values, capacity): best_value = 0 for r in range(len(weights)+1): for subset in combinations(range(len(weights)), r): total_weight = sum(weights[i] for i in subset) total_value = sum(values[i] for i in subset) if total_weight <= capacity and total_value > best_value: best_value = total_value return best_value ``` --- #### 遗传算法 遗传算法是一种基于进化论原理的启发式搜索方法。它通过模拟自然界的基因变异、交叉等过程寻找近似最优解。尽管无法保证全局最优,但在大规模数据集中表现良好[^3]。 以下是伪代码描述: 1. 初始化种群; 2. 计算适应度函数(即目标函数值); 3. 进行选择操作; 4. 执行交叉与变异操作; 5. 判断终止条件是否满足;如果不满足则返回步骤2。 --- #### 模拟退火算法 模拟退火算法模仿金属冷却过程中原子结构变化的过程,用于寻找全局最优解。相比其他局部搜索策略,它可以跳出局部极值点继续探索更优区域[^2]。 主要参数包括初始温度、降温速率以及停止准则等。具体实现依赖于随机数生成器调整候选解并接受概率公式决定下一步方向。 --- #### 贪心算法 贪心算法按照某种规则优先挑选某些特定属性较高的项目加入集合直到不能再加为止。例如按单位重量对应的价值排序后逐一尝试放入包内直至满载或无合适选项可选[^3]。 然而需要注意的是这种简化方式通常得不到精确答案因为忽略了整体关系只关注单步利益最大化可能导致最终结果偏离实际最大收益较多。 --- ### 各算法性能对比总结表 | **算法名称** | **时间复杂度** | **适用场景** | |------------------|--------------------|--------------------------------| | 动态规划 | \(O(nC)\) | 中小型输入尺寸 | | 蛮力法 | \(O(2^n)\) | 极少数非常简单的测试案例 | | 遗传算法 | 取决于迭代次数 | 较大数据集下的次优解决方案获取 | | 模拟退火算法 | 取决于冷却计划设置 | 寻找接近全局最优的结果 | | 贪心算法 | \(O(n\log{n})\) | 对快速估算感兴趣而非绝对准确性场合 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值