小红不想做完全背包(easy)
题目描述
本题和hard版本的唯一区别是:p保证等于3。
完全背包是一个经典问题,但小红完全不会完全背包,因此她不想做完全背包。
现在小红拿到了一个长的很像完全背包的题,她希望你帮她解决一下。
给定一个背包,有n种物品,每种物品的价值为ai,有无穷多个。小红有一个无穷大的背包她希望往里面放若干个物品,使得最终所有物品的价值之和为p的倍数。小红想知道最终至少要放多少物品?(注意:不能不放物品)
输入描述:
第一行输入两个正整数n,p,用空格隔开。第二行输入n个正整数ai。1≤n≤2000,p=3,1≤ai≤10^9.
输出描述:
一个整数,代表小红最终要放的物品数量的最小值。
输入
4 3
1 2 3 4
输出
1
说明
小红只需要选择一个第三种物品即可。
#include<iostream> #include<bits/stdc++.h> #include<vector> using namespace std; int main() { int n, p; cin>>n>>p; int a[2001]; for (int i = 0; i < n; i++) { cin>>a[i]; } int x=0,y=0,z=0; for(int i=0;i<n;i++) { if(a[i]%3==0) { x++; } if(a[i]%3==1) { y++; } if(a[i]%3==2) { z++; } } if(x!=0) { cout<<"1"; } else if(x==0&&y!=0&&z!=0){ cout<<"2"; } else{ cout<<"3"; } return 0; }
小红不想做完全背包 (hard)
p没有必须等于3的限制,1≤n,p≤2000,其余条件均一致
#include<iostream> #include<vector> #include<bits/stdc++.h> using namespace std; typedef long long ll; int main() { int n,p; cin>>n>>p; vector<ll>a(n); set<ll>h; bool flag=false; for(int i=0;i<n;i++){ cin>>a[i]; a[i]%=p; if(a[i]==0) flag=true; h.emplace(a[i]); } if(flag){ cout<<1; return 0; } vector<int>dist(2003,1e9); queue<pair<int,int>>q; for(auto&x:h){ dist[x]=1; q.push({dist[x],x}); } while(!q.empty()){ int s=q.front().second,cnt=q.front().first; q.pop(); for(auto&x:h){ if(dist[(s+x)%p]>cnt+1){ dist[(s+x)%p]=cnt+1; q.push({cnt+1,(s+x)%p}); } } } cout<<dist[0]; return 0; }
- 输入整数
n
(序列长度)和p
(模数)。 - 定义一个
vector
a
存储输入的整数序列,并对序列中的每个元素执行模p
运算。 - 创建一个集合h 存储序列中所有元素的模
p
后的唯一值,并设置一个标志变量flag
,若发现0(模p
后),则直接输出1(因为0本身就是目标值,不需要任何操作)并结束程序。 - 定义一个大小为
2003
的vector
dist
,初始化所有元素为极大值1e9
,用于记录从集合s
中每个元素出发到达0(模p
后)所需的最短步数。同时,创建一个队列q
,用于广度优先搜索(BFS)算法。 - 遍历集合
s
,将每个元素的初始距离(步数)设为1,并加入队列q
。 - 开始执行广度优先搜索算法,循环处理队列
q
中的元素,每次取出一个元素(记为s
)和它的步数cnt
,然后检查能否通过加这个元素s
从其他元素到达新的模p
后的值,并更新dist
数组中的最短步数,如果新的步数小于之前的记录,则将新值和步数加入队列q
。 - 当队列
q
为空时,搜索结束。此时,dist[0]
即为从集合s
中任意一个元素出发,通过加法操作到达模p
后的0所需的最短步数。 - 输出
dist[0]
作为答案。