0/1背包问题(搜索算法)
前言
01背包是在M件物品取出若干件放在空间为W的背包里,每件物品的体积为W1,W2至Wn,与之相对应的价值为P1,P2至Pn。01背包是背包问题中最简单的问题。
01背包的约束条件是给定几种物品,每种物品有且只有一个,并且有权值和体积两个属性。
在01背包问题中,因为每种物品只有一个,对于每个物品只需要考虑选与不选两种情况。如果不选择将其放入背包中,则不需要处理。
如果选择将其放入背包中,由于不清楚之前放入的物品占据了多大的空间,需要枚举将这个物品放入背包后可能占据背包空间的所有情况。
一、题目
0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求而且重量和恰好为W具有最大的价值。
输入格式:
第一行输入背包载重量W及背包个数n,再依次输入n行,每行为背包重量wi和价值vi。
输出格式:
第一行输出装入背包内的物体编号(末尾有空格),若没有任何物品能装入,输出: No,第二行输出背包内的物体总价值。
输入样例1:
5 10
2 6
2 3
6 5
5 4
4 6
结尾无空行
输出样例1:
1 2 5
15
结尾无空行
输入样例2:
2 10
11 2
13 100
结尾无空行
输出样例2:
No
0
二、解答
1.思路
在递归中进行判断,先判断该物品重量和背包剩余重量的大小,若背包的小,直接判断剩下的n-1个物品。
若背包的大,有判断方法:该物品选或者不选(1/0)两种,并从这两中选法分别向后在判断。(若不选就判断剩下n-1个物品,价值不变,背包重量不变;若选,价值加上该物品价值,背包剩余重量减去该物品重量,再判断剩下物品。)
2.代码
代码如下:
#include <stdio.h>
#include <stdlib.h>
int w,n;
struct Node
{
int wi,vi;
}a[100010];//背包
int vis[100010];//判断是否访问过
int max=-10;//保存最大价值
int rem[100010];//保存最大价值下的物品(选了的物品为1,没选的为2)
void dfs(int w,int v,int x)//深搜
{
if(x>n)//当超过背包范围
{
if(v>max)//超过最大价值时,存储该价值下的物品
{
max=v;
memset(rem,0,sizeof(int));//置为0,清空原来存储的
for(int i=0;i<=n;i++)
{
rem[i]=vis[i];
}
}
return;
}
for(int i=0;i<=1;i++)//每个点,0没选,1选了
{
vis[x]=i;
if(a[x].wi*vis[x]<=w)
{
dfs((w-a[x].wi*vis[x]),(v+vis[x]*a[x].vi),x+1);//选与没选条件下进行的深搜
}
}
}
int main()
{
scanf("%d%d",&n,&w);
int wi,vi;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&wi,&vi);
a[i].wi=wi;
a[i].vi=vi;
}
dfs(w,0,1);
if(max<=0)//若没有任何物品能装入时,输出No
{
printf("No\n0");
return 0;
}
for(int i=1;i<=n;i++)
if(rem[i]!=0)
printf("%d ",i);
printf("\n%d",max);
}
总结
0/1 背包问题解决就在于选与不选
202110181935一