小苯的排列构造,小苯的01背包(easy),小苯的01背包(hard)

简介: 小苯的排列构造,小苯的01背包(easy),小苯的01背包(hard)

小苯的排列构造

题目描述

运行代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 1000050
int i,j,k,n,m,t,a[N],b[N],f[N],l[N];
bool v[N];
int main(){
  cin>>n;
  for(i=1;i<=n;i++)
        cin>>a[i];
  v[0]=1;
  for(i=1;i<=n;i++){
    if(a[i-1]%a[i])
        {
            cout<<-1;
            return 0;
        }   
    while(v[l[a[i]]])
            l[a[i]]+=a[i];
    v[l[a[i]]]=1;
        f[i]=l[a[i]];
  }
  for(i=1;i<=n;i++)
        cout<<f[i]<<' ';
}

代码思路

  1. 读取整数序列 a[1], a[2], ..., a[n]
  2. 遍历序列,对于每个 a[i],确保 a[i] 能够整除其前一个数 a[i-1](除了第一个数 a[1],因为它没有前一个数)。
  3. 使用一个数组 l 来存储每个数 x 的当前可能位置或标签。例如,l[x] 表示当前值为 x 的数应该被放置在哪个位置。
  4. 使用一个布尔数组 v 来标记哪些位置已经被使用了。
  5. 对于每个 a[i]:如果 a[i] 不能整除其前一个数(除了第一个数 a[1]),则输出 -1 并终止程序。否则,在 l[a[i]] 开始,向后查找第一个未被使用的位(即 v[l[a[i]]]false 的位置)。将找到的位置标记为已使用(v[l[a[i]] + k*a[i]] = true,其中 k 是使得该位置未被使用的最小整数)。将 f[i] 设置为找到的位置 l[a[i]] + k*a[i]
  6. 输出所有的 f[i]

小苯的01背包(easy)

题目描述

运行代码

#include <iostream>
using namespace std;
const int N = 2e5+5;
int v[N],w[N];
int ans;
void solve()
{
    int n,k;
    cin>>n>>k;
    for(int i=0;i<n;i++)
        cin>>v[i]>>w[i];
    for(int i=30;i>=0;i--){
        int sum=ans|(1<<i);
        int v_sum=(1<<30)-1;
        for(int j=0;j<n;j++){
            if((w[j]&sum)==sum) 
                v_sum&=v[j];
        }
        if(v_sum<=k) ans=sum;
    }
    cout<<ans<<endl;
    return;
}
int main()
{
  int f= 1;
  while(f--)
        solve();
  return 0;
}

代码思路

  1. 输入处理:首先读取两个整数nk,表示物品数量和目标价值。然后读取每个物品的价值v[i]和属性w[i]
  2. 位运算优化的动态规划
  • 外层循环从30(即二进制最高位)降到0,这是因为假设属性的位数最多为30位(由(1<<30)-1暗示)。
  • 对于当前位i,计算当前最优解ans加上这一位后的值sum
  • 初始化v_sum(1<<30)-1,代表所有可能的属性集合。
  • 遍历所有物品,检查当前物品的属性集合w[j]是否包含sum的所有位(即w[j] & sum == sum),如果是,则将该物品的价值集合(视为一个二进制位集合)与v_sum进行按位与操作,这样可以逐步筛选出满足条件的最小价值集合。
  • 如果经过上述筛选后得到的v_sum小于等于目标价值k,说明加入这一位是可行的,更新当前最优解ans = sum
  1. 输出结果:最后输出得到的最大属性集合所对应的二进制值ans
  2. 主函数:主函数中通过一个变量f控制解决问题的次数,这里f=1意味着只解决一次问题,然后调用solve()函数执行上述逻辑。

小苯的01背包(hard)

题目描述

运行代码

#include <iostream>
using namespace std;
typedef long long ll;
const int N=2e5+5;
int read() {
    int x = 0, f = 1;
    char c = getchar();
    while(c < '0' || c > '9')
        f = (c == '-') ? -1 : 1, c = getchar();
    while(c >= '0' && c <= '9')
        x = x * 10 + c - 48, c = getchar();
    return f * x;
}
int a[N], v[N], w[N], b[N], n, k;
bool check(int x) {
    int tot = 0;
    for(int i = 1; i <= n; i++)
        if((x & w[i]) == x)
            b[++tot] = i;
    int c = (1 << 31) - 1;
    for(int i = 1; i <= tot; i++)
        c &= v[b[i]];
    if(c <= k)
        return 1;
    return 0;
}
signed main() {
    n = read(), k = read();
    for(int i = 1; i <= n; i++)
        v[i] = read(), w[i] = read();
    int ans = 0;
    for(int i = 30; i >= 0; i--) {
        if(check(ans | (1 << i)))
            ans |= 1 << i;
    }
    cout << ans;
}

代码思路

  1. 输入处理:
  • 使用read()函数自定义读取整数,支持负数,提高了输入效率。
  • 读取项目数量n和价值阈值k,以及每个项目的具体价值v[i]和属性w[i]
  1. check函数:
  • 输入一个整数x,表示当前考虑的属性集合。
  • 遍历所有项目,如果项目i的属性集合w[i]x的子集(即(x & w[i]) == x),则将该项目的索引存入数组b[]
  • 计算所有符合条件的项目价值集合的交集(通过按位与运算),并检查这个交集的值是否不大于k。如果满足条件,返回true;否则,返回false
  1. 主函数逻辑:
  • 初始化答案ans为0,表示当前考虑的最优属性集合。
  • 从最高位到最低位遍历(即从第30位到第0位),对于每一位:尝试将这一位置为1(即在当前最优解基础上增加这一位的属性),然后检查这一改变是否仍然满足总价值不超过k的条件,这通过调用check()函数完成。如果满足条件,就保留这一位的修改(即这一位在最终解中应为1);如果不满足,就尝试下一位。
  • 最终输出得到的属性集合的二进制表示ans

利用了位运算来高效地处理集合的合并与判断,通过逐位检查的方式构建出满足条件的最优属性集合,相比直接的暴力枚举或者传统动态规划方法,在处理大规模数据时能显著提高效率。

目录
相关文章
|
2月前
|
消息中间件 Kubernetes JavaScript
动态规划-区间、计数类DP问题总结
动态规划-区间、计数类DP问题总结
|
2月前
|
算法 Windows
class073 背包dp-01背包、有依赖的背包【算法】
class073 背包dp-01背包、有依赖的背包【算法】
45 0
|
2月前
【错题集-编程题】删除相邻数字的最大分数(动态规划 - 线性 dp)
【错题集-编程题】删除相邻数字的最大分数(动态规划 - 线性 dp)
|
2月前
|
算法
算法系列--动态规划--背包问题(2)--01背包拓展题目(下)
算法系列--动态规划--背包问题(2)--01背包拓展题目(下)
28 0
算法系列--动态规划--背包问题(2)--01背包拓展题目(下)
|
2月前
|
算法 C#
算法系列--动态规划--背包问题(1)--01背包介绍(上)
算法系列--动态规划--背包问题(1)--01背包介绍
27 0
|
2月前
|
机器学习/深度学习 算法 C#
算法系列--动态规划--背包问题(1)--01背包介绍(下)
算法系列--动态规划--背包问题(1)--01背包介绍(下)
25 0
|
2月前
|
算法
算法系列--动态规划--背包问题(2)--01背包拓展题目(上)
算法系列--动态规划--背包问题(2)--01背包拓展题目
26 0
|
2月前
|
算法
算法系列--动态规划--背包问题(3)--完全背包介绍(上)
算法系列--动态规划--背包问题(3)--完全背包介绍
26 0
|
2月前
|
算法 测试技术 C#
【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目
【动态规划】【数论】【区间合并】3041. 修改数组后最大化数组中的连续元素数目
|
C++
(排列,选择类dp)(数论同余定理,同余运算)(以背包为母题)1214. 波动数列
(排列,选择类dp)(数论同余定理,同余运算)(以背包为母题)1214. 波动数列
77 0