首页 > 其他 > 详细

小M和天平(01背包问题)

时间:2021-04-20 00:32:57      阅读:40      评论:0      收藏:0      [点我收藏+]

题目:小M和天平

  • 题意:给你n颗石子,这些石子可任意放在称的左边或右边(大的重量-小的重量),问是否可以得出所给的重量。
  • 思路:01背包问题。
  • 解析:
    1. 集合划分:f[i][j]表示前i个石子能否称出重量为j(1:代表可以,0:代表不行)
    2. 状态表示:
    • f[0][0] = 1; //0颗石子可称出重量为0的情况必然存在
    • 若前i-1颗石子可称出重量为j:
      f[i][j] = 1; //不选i颗石子
      f[i][j+w[i]]; //选第i颗石子放在称的右边(放在叠加一侧)
      f[i][abs(j-w[i])]; //选第i颗石子放在称的左边(放在抵消一侧),假若是左侧重,则
      可以计算出左侧的重量-右侧重量,否则计算出右侧重量-左侧重量,所以加绝对值。
  • 代码:
#include<iostream>
#include<cstring>
using namespace std;
const int N = 110;
const int M = 1e4 + 5;
int f[N][M]; //前i个石子能否称出j的重量(1:可以, 0:不可以)
int n, t;
int w[N];

int main()
{
    while(cin >> n)
    {
        for(int i = 1; i <= n; i++) cin >> w[i];
        memset(f, 0, sizeof f);
        f[0][0] = 1;
        for(int i = 1; i <= n; i++)
        {
            for(int j = 0; j <= M; j++) //最多能称1e4重量(或者可对w[i]求一个前缀和)
            {
                if(f[i-1][j])
                {
                    f[i][j] = 1; //不选择第i个石子
                    f[i][j+w[i]] = 1; //选择第i个石子放在右侧进行叠加
                    f[i][abs(j-w[i])] = 1; //选择第i个石子放在左侧进行抵消
                }
            }
        }
        cin >> t;
        while(t --)
        {
            int x;
            cin >> x;
            if(x > 1e4 || !f[n][x]) cout << "NO" << endl;
            else cout << "YES" << endl;
        }
    }
    return 0;
}

小M和天平(01背包问题)

原文:https://www.cnblogs.com/K2MnO4/p/14678726.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!