NC19158 失衡天平(DP)

题目链接

题意:
一 共 有 n 个 武 器 , 每 个 武 器 重 量 为 w i 一共有n个武器,每个武器重量为w_i nwi
有 一 个 天 平 , 往 天 平 两 端 放 武 器 有一个天平,往天平两端放武器
如 果 天 平 两 端 的 重 量 小 于 等 于 m 那 么 可 以 全 部 取 走 如果天平两端的重量小于等于m那么可以全部取走 m
问 最 多 能 取 走 多 少 重 量 武 器 问最多能取走多少重量武器
题解:
n , w i , m < = 100 n,w_i,m<=100 n,wi,m<=100
这 个 天 平 可 以 多 次 取 这个天平可以多次取
但 其 实 思 考 一 下 , 会 发 现 如 果 你 x 次 能 把 某 两 种 物 品 取 走 但其实思考一下,会发现如果你x次能把某两种物品取走 x
那 么 这 2 ∗ x 种 物 品 同 时 放 的 时 候 也 一 定 能 取 走 那么这2*x种物品同时放的时候也一定能取走 2x
只 不 过 是 放 的 顺 序 交 换 一 下 之 类 的 关 系 只不过是放的顺序交换一下之类的关系
所 以 我 们 现 在 需 要 维 护 的 状 态 有 已 枚 举 的 武 器 , 差 值 , 最 大 重 量 所以我们现在需要维护的状态有已枚举的武器,差值,最大重量
所 以 d p 数 组 就 出 来 了 , d p [ i ] [ j ] 表 示 前 i 个 武 器 中 差 值 为 j 的 最 大 重 量 所以dp数组就出来了,dp[i][j]表示前i个武器中差值为j的最大重量 dpdp[i][j]ij
对 于 第 i 种 武 器 的 转 移 方 法 就 是 对于第i种武器的转移方法就是 i
让 差 值 加 这 个 武 器 , 即 把 这 个 武 器 放 到 较 重 的 一 端 让差值加这个武器,即把这个武器放到较重的一端
新 的 差 值 为 这 个 武 器 和 当 前 差 值 的 绝 对 值 , 即 放 到 轻 的 一 段 新的差值为这个武器和当前差值的绝对值,即放到轻的一段
还 有 就 是 不 选 这 个 武 器 , 三 种 方 程 分 别 为 还有就是不选这个武器,三种方程分别为
d p [ i ] [ j + a i ] + a i dp[i][j+a_i]+a_i dp[i][j+ai]+ai
d p [ i ] [ a b s ( j − a i ) ] + a i dp[i][abs(j-a_i)]+a_i dp[i][abs(jai)]+ai
d p [ i ] [ j − 1 ] dp[i][j-1] dp[i][j1]
这 三 种 状 态 取 最 大 即 可 这三种状态取最大即可
最 后 只 要 找 出 差 值 不 超 过 m 的 最 大 重 量 最后只要找出差值不超过m的最大重量 m
AC代码

/*
    Author:zzugzx
    Lang:C++
    Blog:blog.csdn.net/qq_43756519
*/
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define endl '\n'
#define SZ(x) (int)x.size()
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
typedef pair<double,double> pdd;
const int mod=1e9+7;
//const int mod=998244353;
const double eps = 1e-10;
const double pi=acos(-1.0);
const int maxn=1e6+10;
const ll inf=0x3f3f3f3f;
const int dir[8][2]={{0,1},{1,0},{0,-1},{-1,0},{1,1},{1,-1},{-1,1},{-1,-1}};

int dp[110][11000],a[110];

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);cout.tie(0);
    //freopen("in.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    int n,m,N=10000;
    cin>>n>>m;
    for(int i=1;i<=n;i++)cin>>a[i];
    memset(dp,-inf,sizeof dp);
    dp[0][0]=0;
    for(int i=1;i<=n;i++)
        for(int j=0;j<=N;j++){
            dp[i][j]=dp[i-1][j];
            int tmp=max(dp[i-1][j+a[i]]+a[i],dp[i-1][abs(j-a[i])]+a[i]);
            dp[i][j]=max(dp[i][j],tmp);
        }
    int ans=0;
    for(int i=0;i<=m;i++)
        ans=max(ans,dp[n][i]);
    cout<<ans;
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值