算法设计与分析-回溯法

单选题

关于回溯法以下叙述中不正确的是( )。
A. 回溯法有“通用解题法”之称,它可以系统地搜索一个问题的所有解或任意解
B. 回溯法是一种既带系统性又带跳跃性的搜索算法
C. 回溯法需要借助队列这种结构来保存从根结点到当前扩展结点的路径
D. 回溯算法在生成解空间的任一结点时先判断该结点是否可能包含问题的解,如果肯定不包含,则跳过对该结点为根的子树的搜索,逐层向祖先结点回溯

回溯法在问题的解空间树中,按( )策略,从根结点出发搜索解空间树。
A. 广度优先
B. 活结点优先
C. 扩展结点优先
D. 深度优先

回溯法的效率不依赖于下列哪些因素
A. 满足显约束的值的个数
B. 计算约束函数的时间
C. 计算限界函数的时间
D. 确定解空间的时间

下面哪种函数是回溯法中为避免无效搜索采取的策略
A. 递归函数
B. 剪枝函数
C. 随机数函数
D. 搜索函数

下列程序块哪个是回溯法中遍历排列树的算法框架程序。

A. void backtrack (int t)
{
if (t>n) output(x);
 else
  for (int i=t;i<=n;i++) {
    swap(x[t], x[i]);
    if (legal(t)) backtrack(t+1);
    swap(x[t], x[i]);
  }     
}

 C. void backtrack (int t)
{
if (t>n) output(x);
else
  for (int i=0;i<=1;i++) {
    x[t]=i;
    if (legal(t)) backtrack(t-1);
  }
}

 C. void backtrack (int t)
{
if (t>n) output(x);
else
  for (int i=0;i<=1;i++) {
    x[t]=i;
    if (legal(t)) backtrack(t-1);
  }
}

 D. void backtrack (int t)
{
if (t>n) output(x);
else
  for (int i=t;i<=n;i++) {
    swap(x[t], x[i]);
    if (legal(t)) backtrack(t+1);
  }
}

程序填空题

求解简单装载问题(回溯法)

有n个集装箱要装上一艘载重量为W的轮船,其中集装箱i(1≤i≤n)的重量为wi。不考虑集装箱的体积限制,现要这些集装箱中选出若干装上轮船,使它们的重量之和等于W,当总重量相同时要求选取的集装箱个数尽可能少。

#include <stdio.h>
#include <string.h>
#include <iostream>
using namespace std;
#define MAXN 20                        //最多集装箱个数
//问题表示
int w[MAXN]={0};                //各集装箱重量,不用下标0的元素
int    n,W;
int maxw;                            //存放最优解的总重量
int x[MAXN];                        //存放最优解向量
int minnum=999999;                    //存放最优解的集装箱个数,初值为最大值
void dfs(int num,int tw,int rw,int op[],int i) //考虑第i个集装箱
{
    if (i>n)                        //找到一个叶子结点
    {
        if (tw==W && num<minnum)
        {    
            maxw=tw;                //找到一个满足条件的更优解
            minnum=num;
            for (int j=1;j<=n;j++)
                x[j]=op[j];
        }
    }
    else                        //尚未找完所有集装箱
    {    op[i]=1;                //选取第i个集装箱
        if (tw+w[i]<=W)            //左孩子结点剪枝:装载满足条件的集装箱
            dfs(num+1,tw+w[i],rw-w[i],op,i+1);
        op[i]=0;                //不选取第i个集装箱,回溯
        if (tw+rw>W)            //右孩子结点剪枝
            dfs(num,tw,rw-w[i],op,i+1);
    }
}

void dispasolution(int n)        //输出一个解
{
    for (int i=1;i<=n;i++)
        if (x[i]==1)
            printf("%d ",i);
}
int main()
{
    int i;
    cin>>n>>W; 
    for(int i=1;i<=n;i++) 
        cin>>w[i];    
    int op[MAXN];                //存放临时解
    memset(op,0,sizeof(op));
    int rw=0;
    for (int i=1;i<=n;i++)
        rw+=w[i];
    dfs(0,0,rw,op,0);
    dispasolution(n);
    return 0;
}

输入格式:

第一行输入集装箱个数n和载重量W,第二行依次输入n个集装箱的重量wi。

输出格式:

输出选取的集装箱编号(按输入顺序从1开始依次编号)。

输入样例1:

5 10

5 2 6 4 3

输出样例1:

3 4

 求子集(幂集)问题(回溯法)

有一个含n个数的数组a,所有元素均不相同,设计一个算法求其所有子集(幂集)。

输入格式:

第一行输入元素个数n,再依次输入n个数。

输出格式:

逐行输出每个解

输入样例1:

3

1 2 3

输出样例1:

{}
{3}
{2}
{2,3}
{1}
{1,3}
{1,2}
{1,2,3}

 #include <stdio.h>
#include <string.h>
#define MAXN 100
void dispasolution(int a[],int n,int x[])    //输出一个解
{
    printf("{");
    int f=0;
    for (int i=0;i<n;i++){
        if (x[i]==1&&f==0)
            {
                printf("%d",a[i]);f++;
            }
        else if (x[i]==1&&f>0)
            printf(",%d",a[i]);        
    }
    printf("}\n");
}
void dfs(int a[],int n,int i,int x[])    //回溯算法
{
    if (i>=n)
        dispasolution(a,n,x);
    else
    {
        x[i]=0;
        dfs(a,n,i+1,x);    
        x[i]=1;
        dfs(a,n,i+1,x);    
    }
}
int main()
{    
    int a[MAXN];                
    int n;
    int x[MAXN];                
    memset(x,0,sizeof(x));        
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%d",&a[i]);
    dfs(a,n,0,x);
    return 0;
}

 0/1背包问题(回溯法)

0/1背包问题。给定一载重量为W的背包及n个重量为wi、价值为vi的物体,1≤i≤n,要求而且重量和恰好为W具有最大的价值。

#include <stdio.h>
#include <string.h>
#include <iostream>
#define MAXN 20                //最多物品数
using namespace std;
int n;                        //物品数
int W;                        //限制重量
int w[MAXN]={0};            //存放物品重量,不用下标0元素
int v[MAXN]={0};            //存放物品价值,不用下标0元素
int x[MAXN];                    //存放最终解
int maxv;                         //存放最优解的总价值
void dfs(int i,int tw,int tv,int rw,int op[]) //求解0/1背包问题
{
    int j;
    if (i>n)                    //找到一个叶子结点
    {    if (tw ==W&&tv>maxv)     //找到一个满足条件的更优解,保存它
        {    maxv=tv;
            for (int j=1;j<=n;j++)    //复制最优解
                x[j]=op[j];
        }
    }
    else                        //尚未找完所有物品
    {    if (tw+w[i]<=W)          //左孩子结点剪枝:满足条件时才放入第i个物品
        {
            op[i]=1;            //选取第i个物品
            dfs(i+1,tw+w[i],tv+v[i],rw-w[i],op);
        }
        op[i]=0;                //不选取第i个物品,回溯
        if (tw+rw-w[i]>=W)            //右孩子结点剪枝
            dfs(i+1,tw,tv,rw-w[i],op);
    }
}
void dispasolution()            //输出最优解
{    int i;
    for (i=1;i<=n;i++)
        if (x[i]==1)
            printf("%d ",i);
    printf("\n%d %d",W,maxv);
}
int main()
{
    int i;
    cin>>n>>W; //输入物体个数及背包载重量 
    for(int i=1;i<=n;i++)//输入各物体重量及价值 
        cin>>w[i]>>v[i];
    int op[MAXN];                //存放临时解
    memset(op,0,sizeof(op));
    int rw=0;
    for (int i=1;i<=n;i++)
        rw+=w[i];
    dfs(1,0,0,rw,op);
    dispasolution();
    return 0;
}

 

输入格式:

第一行输入背包载重量W及背包个数n,再依次输入n行,每行为背包重量wi和价值vi。

输出格式:

第一行输出输出装入背包内的物体编号(末尾有空格),第二行输出背包内的物体总重量和总价值。

输入样例1:

5 10

2 6

2 3

6 5

5 4

4 6

输出样例1:

1 2 3

10 14

 1-9数字间插入加减号计算结果为100问题(回溯法)

设计一个算法在1、2、...、9(顺序不能变)数字之间插入+或-或什么都不插入,使得计算结果总是100的程序,并输出所有的可能性。

输出格式:

逐行输出每个解

输出样例1:

1+2+3-4+5+6+78+9=100
1+2+34-5+67-8+9=100
1+23-4+5+6+78-9=100
1+23-4+56+7+8+9=100
12+3+4+5-6-7+89=100
12+3-4+5+67+8+9=100
12-3-4+5-6+7+89=100
123+4-5+67-89=100
123+45-67+8-9=100
123-4-5-6-7+8-9=100
123-45-67+89=100

#include <stdio.h>
#define N 9
void fun(char op[],int sum,int prevadd,int a[],int i)
{
    if (i == N)                        //扫描完所有位置
    {
        if (sum == 100)                //找到一个解
        {
            printf("%d",a[0]);    //输出解
            for (int j=1;j<N;j++)
            {
                if (op[j]!=' ')
                    printf("%c",op[j]);
                printf("%d",a[j]);
            }
            printf("=100\n");
        }
        return;
    }
    op[i]='+';                        //位置i插入'+'
    sum+=a[i];                        //计算结果
    fun(op,sum,a[i],a,i+1);            //继续处理下一个位置
    sum -= a[i];                        //回溯

    op[i]='-';                        //位置i插入'-'
    sum-=a[i];                        //计算结果
    fun(op,sum,-a[i],a,i+1);        //继续处理下一个位置
    sum += a[i];                        //回溯

    op[i]=' ';                        //位置i插入' '
    sum-=prevadd;                    //先减去前面的元素值
    int tmp;                        //计算新元素值
    if (prevadd>0)
        tmp=prevadd*10+a[i];        //如prevadd=5,a[i]=6,结果为56
    else
        tmp=prevadd*10-a[i];        //如prevadd=-5,a[i]=6,结果为-56
    sum+=tmp;                        //计算合并结果
    fun(op,sum,tmp,a,i+1);            //继续处理下一个位置
    sum-=tmp;                        //回溯sum
    sum+=prevadd;
}
int main()
{
    int a[N];
    char op[N];                    //op[i]表示在位置i插入运算符
    for (int i=0;i<N;i++)        //为a赋值为1,2,...,9
        a[i]=i+1;
    fun(op,a[0],a[0],a,1);        //插入位置i从1开始
    return 0;
}

 

 求解活动安排问题(回溯法)

假设有一个需要使用某一资源的n个活动所组成的集合S,S={1,…,n}。该资源任何时刻只能被一个活动所占用,活动i有一个开始时间bi和结束时间ei(bi<ei),其执行时间为ei-bi,假设最早活动执行时间为0。
一旦某个活动开始执行,中间不能被打断,直到其执行完毕。若活动i和活动j有bi≥ej或bj≥ei,则称这两个活动兼容。
设计算法求一种最优活动安排方案,使得所有安排的活动个数最多。

#include <stdio.h>
#include <string.h>
#include <iostream>
#define MAX 51
using namespace std;
//问题表示
struct Action
{
    int b;                    //活动起始时间
    int e;                    //活动结束时间
};
int n=4;
Action A[MAX]={{0,0}};        //下标0不用
//求解结果表示
int x[MAX];                    //解向量
int bestx[MAX];                //最优解向量
int laste=0;                //一个方案中最后兼容活动的结束时间
int sum=0;                    //一个方案中所有兼容活动个数
int maxsum=0;                //最优方案中所有兼容活动个数

void swap(int &x,int &y)    //交换x、y
{    int tmp=x;    x=y; y=tmp;}

void dispasolution()                    //输出一个解
{
    int laste=0;
    for (int j=1;j<=n;j++)
    {
        if (A[bestx[j]].b>=laste)        //选取活动bestx[j]
        {
            printf("[%d,%d)\n",A[bestx[j]].b,A[bestx[j]].e);
            laste=A[bestx[j]].e;
        }
    }
    printf("%d",maxsum);
}

void action(int i)                            
{
    if (i>n)                
    {
        if (sum>maxsum)
        {
            maxsum=sum;
            for (int k=1;k<=n;k++)
                bestx[k] = x[k];
        }
    }
    else
    {
        for(int j=i; j<=n; j++)                
        {    
            int sum1=sum;            
            int laste1=laste;
            if (A[x[j]].b>=laste)        
            {
                sum++;                
                laste = A[x[j]].e;        
            }
            swap(x[i],x[j]);                
            action(i+1);                
            swap(x[i],x[j]);    
            sum=sum1;        
            laste=laste1;                    
        }
    }
}

int main()
{
    cin>>n;
    for (int i=1;i<=n;i++)
       cin>>A[i].b>>A[i].e;    
    for (int i=1;i<=n;i++)
        x[i]=i;
    action(1);                                //i从1开始搜索
    dispasolution();                    //输出结果
    return 0;
}

 

输入格式:

第一行是一个整数n,接着的n行中每一行包括两个整数b和e,其中b是一个订单开始时间,e是的结束时间。。

输出格式:

若count表示最大兼容活动集合数,先输出count行,每行为活动的开始时间和结束时间。最后输出count。

输入样例1:

4
1 3
2 5
4 8
6 10

输出样例1:

 [1,3)
 [4,8)
 2

 求解图的m着色问题(回溯法)

给定无向连通图G和m种不同的颜色。用这些颜色为图G的各顶点着色,每个顶点着一种颜色。如果有一种着色法使G中每条边的两个顶点着不同颜色,则称这个图是m可着色的。图的m着色问题是对于给定图G和m种颜色,找出所有不同的着色法。

裁判测试程序样例:

#include <stdio.h>
#include <string.h>
#define MAXN 20                //图最多的顶点个数
int n,k,m;
int a[MAXN][MAXN];
int count=0;                //全局变量,累计解个数
int x[MAXN];                //全局变量,x[i]表示顶点i的着色

bool Same(int i)            //判断顶点i是否与相邻顶点存在相同的着色
{
    for (int j=1;j<=n;j++)
        if (a[i][j]==1&&x[i]==x[j])
            return false;
    return true;
}
void dfs(int i)                    //求解图的m着色问题
{
    if (i>n)                    
    {
        count++;            
    }
    else
    {
        for (int j=1;j<=m;j++)    
        {
            x[i]=j;
            if (Same(i))        
                dfs(i+1);
            x[i]=0;            
        }
    }
}
int main()
{
    memset(a,0,sizeof(a));        //a初始化
    memset(x,0,sizeof(x));        //x初始化
    int x,y;
    scanf("%d%d%d",&n,&k,&m);    //输入n,k,m
    for (int j=1;j<=k;j++)
    {
        scanf("%d%d",&x,&y);    //输入一条边的两个顶点
        a[x][y]=1;                //无向图的边对称
        a[y][x]=1;
    }
    dfs(1);                        //从顶点1开始搜索
    if (count>0)                //输出结果
        printf("%d",count);
    else
        printf("-1");
    return 0;
}

 

输出格式:

程序运行结束时,将计算出的不同的着色方案数输出。如果不能着色,程序输出-1。

输入样例:

5 8 4
1 2
1 3
1 4
2 3
2 4
2 5
3 4
4 5

输出样例:

48

 函数题

输出全排列

请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。
输入格式:
输入给出正整数n(<10)。
输出格式:
输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a1​,a2​,⋯,an​排在序列b1​,b2​,⋯bn​之前,如果存在k使得a1​=b1​,⋯,ak​=bk​ 且 ak+1​<bk+1​。

函数接口定义:

void recursion(int a[],int k); //求a数组元素的全排列

裁判测试程序样例:

#include <stdio.h>
int order[10];//将产生的一个序列保存到order中
int is_mark[10]; // is_mark[i]==1表示元素a[i]被选中,is_mark[i]==0表示元素a[i]未被选中
int n;
void recursion(int a[],int k); //求a数组元素的全排列
int main ()
{int i,a[10];
    scanf ("%d",&n);
    for(i=0;i<n;i++)
    {
        a[i]=i+1;
    }
    recursion(a,1);
    return 0;
}

/* 请在这里填写答案 */

 

 

输入样例:

在这里给出一组输入。例如:

3

输出样例:

在这里给出相应的输出。例如:

123
132
213
231
312
321

void  recursion(int a[],int k)
{
    if(k>n) 
    {
        for(int i=1;i<=n;i++) printf("%d",order[i]);
        printf("\n");
        return ;
    }
    for(int i=1;i<=n;i++)
    {
        if(!is_mark[i])
        {
            order[k]=i;
            is_mark[i]=1;
            recursion(a,k+1);
            order[k]=0;
            is_mark[i]=0;
        }
    }
}

 

 求子集和问题(回溯法)

给定n个不同的正整数集合w=(w1,w2,…,wn)和一个正数W,要求找出w的子集s,使该子集中所有元素的和为W。

函数接口定义:

void dfs(int tw,int rw,int x[],int i);

其中 tw 表示选取的整数和,rw表示余下的整数和,x[]表示一个解,i表示考虑的第i个数

裁判测试程序样例:

#include <stdio.h>
#include <iostream>
using namespace std;
#define MAXN 20                        //最多整数个数

int n,W;
int w[MAXN]={0};                //存放所有整数,不用下标0的元素
void dispasolution(int x[])            //输出一个解
{    int i;
    for (i=1;i<=n;i++)
        if (x[i]==1)
            printf("%d ",w[i]);
    printf("\n");
}
void dfs(int tw,int rw,int x[],int i);

int main()
{   cin>>n>>W;
    for(int i=1;i<=n;i++)
      cin>>w[i]; 
    int x[MAXN];                    //存放一个解向量
    int rw=0;
    for (int j=1;j<=n;j++)            //求所有整数和rw
        rw+=w[j];
    dfs(0,rw,x,1);                //i从1开始
    return 0;
}

/* 请在这里填写答案 */

 

 

输入格式:

第一行输入n和W,第二行依次输入n个数。

输出格式:

每行输出一个符合要求的子集。

输入样例1:

4 31
11 13 24 7

输出样例1:

11 13 7 
24 7   

void dfs(int tw,int rw,int x[],int i)
{
    if(i>n)
    {
        if(tw==W) dispasolution(x);
    }
    else
    {
        if(tw+w[i]<=W)
        {
            x[i]=1;
            dfs(tw+w[i],rw-w[i],x,i+1);
        }
        if(tw+rw-w[i]>=W)
        {
            x[i]=0;
            dfs(tw,rw-w[i],x,i+1);
        }
    }
}

 编程题

0-1背包

给定n(n<=100)种物品和一个背包。物品i的重量是wi(wi<=100),价值为vi(vi<=100),背包的容量为C(C<=1000)。
应如何选择装入背包中的物品,使得装入背包中物品的总价值最大? 在选择装入背包的物品时,对每种物品i只有两个选择:装入或不装入。不能将物品i装入多次,也不能只装入部分物品i。

输入格式:

共有n+1行输入:
第一行为n值和c值,表示n件物品和背包容量c;
接下来的n行,每行有两个数据,分别表示第i(1≤i≤n)件物品的重量和价值。

输出格式:

输出装入背包中物品的最大总价值。

输入样例:

在这里给出一组输入。例如:

5 10
2 6
2 3
6 5
5 4
4 6

输出样例:

在这里给出相应的输出。例如:

15
#include<iostream>
using namespace std;
const int N = 1005;
int n,c,w[N],v[N],dp[N][N];
int main()
{
    scanf("%d %d",&n,&c);
    for(int i=1;i<=n;i++) scanf("%d %d",&w[i],&v[i]);
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<=c;j++)
        {
            dp[i][j]=dp[i-1][j];
            if(j>=w[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+v[i]);
        }
    }
    printf("%d",dp[n][c]);
    return 0;
}

 

子集和问题

给定n个不同的正整数集合w=(w1,w2,…,wn)和一个正数W,要求找出w的子集s,使该子集中所有元素的和为W。

输入格式:

第一行输入n和W,第二行依次输入n个数。

输出格式:

每行输出一个符合要求的子集。

输入样例1:

4 31
11 13 24 7

输出样例1:

11 13 7 
24 7 
#include<iostream>
using namespace std;
int n,w,a[100],sum,t[100];
void dfs(int u)
{
    if(u==n)
    {
        if(sum==w)
        {
            for(int i=0;i<n;i++) if(t[i]) cout<<a[i]<<" ";
            cout<<endl;
        }
        return ;
    }
    else
    {
        sum+=a[u];
        t[u]=1;
        dfs(u+1);
        t[u]=0;
        sum-=a[u];
        dfs(u+1);
    }
}
int main()
{
    cin>>n>>w;
    for(int i=0;i<n;i++) cin>>a[i];
    dfs(0);
    return 0;
}

幂集(回溯法)

有一个含n个数的数组a,所有元素均不相同,设计一个算法求其所有子集(幂集)。
例如:1 2 3的幂集{}、{3}、{2}、{2,3}、{1}、{1,3}、{1,2}、{1,2,3}

输入格式:

第一行输入元素个数n,再依次输入n个数。

输出格式:

输出子集数

输入样例1:

3
1 2 3

输出样例1:

8
#include <iostream>
#include <cmath>
using namespace std;
int qpow(int a,int b)
{
    int res=1;
    while(b)
    {
        if(b&1) res*=a;
        a=a*a;
        b>>=1;
    }
    return res;
}
int main()
{
    int n,x;
    cin>>n;
    int res=qpow(2,n);
    printf("%d",res);
    return 0;
    
}

 h0154.加勒比海盗船——最优装载问题

 

 

在北美洲东南部,有一片神秘的海域,那里碧海 蓝天、阳光明媚,这正是传说中海盗最活跃的加勒比 海(Caribbean Sea)。17 世纪时,这里更是欧洲大陆 的商旅舰队到达美洲的必经之地,所以当时的海盗活 动非常猖獗,海盗不仅攻击过往商人,甚至攻击英国 皇家舰……
有一天,海盗们截获了一艘装满各种各样古董的 货船,每一件古董都价值连城,一旦打碎就失去了它 的价值。虽然海盗船足够大,但载重量为 C,每件古 董的重量为 wi,海盗们该如何把尽可能多数量的宝贝 装上海盗船呢?

输入格式:

第1行输入T组测试数据,每组测试数据输入载重量 c 及古董个数 n,下1行输入每个古董的重量wi,用空格分开.

输出格式:

每组能装入的古董最大数量

输入样例:

1
30 8
4 10 7 11 3 5 14 2

输出样例:

5
#include<iostream>
#include <algorithm>
using namespace std;
int T,c,n;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        int t=0,sum=0;
        scanf("%d %d",&c,&n);
        int w[n+1];
        for(int i=0;i<n;i++) scanf("%d",&w[i]);
        sort(w,w+n);
        for(int i=0;i<n;i++)
        {
            sum+=w[i];
            if(sum>c)
            {
                printf("%d\n",i);
                break;
            }
        }
    }
    return 0;
}

 01背包

事情是这样的,jzk要去爬山,但是他的包容量有限,可是他需要非常多的能量,要不然就很容易饿。
第一行给出jzk准备爬几次山。
每次爬山都会带新的包(因为jzk每用一个包都会被zwg抢过去),和准备新的食物(因为每次剩下来的都被zwg吃了)。
下一行给你这一次食物的数目n,和背包容量k,
接下来的一行给出n个食物的能量,再一行给出n个食物的大小(占背包的容量)。
请帮助jzk计算他最多可以带多少能量的食物去爬山。输出可以携带食物的最大能量和。
(n,m<1000) 能量和食物均小于40000

输入格式:

第一行包含整数T,表示有T组案例。

接着是T组案例,每组案例三行,第一行包含两个整数N,M,(N<=1000,M<=1000),表示物品数量和袋子的体积。第二行包含表示每个物品能量的n个整数。第三行包含代表每个物品体积的n个整数。

输出格式:

每组案例一行,只输出一个数字,表示jzk可以获得的最大能量。

输入样例:

在这里给出一组输入。例如:

1
5 10
1 2 3 4 5
5 4 3 2 1

输出样例:

在这里给出相应的输出。例如:

14

TIPS:

(包容量是10)可以带第2,3,4,5,个食物,2 + 3 +4 +5 = 14

 

#include<iostream>
#include<cstring>
using namespace std;
#define f(x) memset(x,0,sizeof x)
const int N = 1005;
int n,m,w[N],v[N],dp[N][N],T;
int main()
{
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d %d",&n,&m);
        f(w),f(v),f(dp);
        for(int i=1;i<=n;i++) scanf("%d",&v[i]);
        for(int i=1;i<=n;i++) scanf("%d",&w[i]);
        for(int i=1;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
            {
                dp[i][j]=dp[i-1][j];
                if(j>=w[i]) dp[i][j]=max(dp[i][j],dp[i-1][j-w[i]]+v[i]);
            }
        }
        printf("%d\n",dp[n][m]);
    }
    return 0;
}

0/1背包问题

 

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
#include<iostream>
using namespace std;
const int N=1005;
int n,W,maxv,t;
int w[N],v[N],x[N],op[N];
void dfs(int i,int tw,int tv,int op[])
{
    if(i>n)
    {
        if(tv>maxv)
        {
            maxv=tv;
            for(int j=1;j<=n;j++)
                x[j]=op[j];
        }
    }
    else
    {
        if(tw+w[i]<=W)
        {
            op[i]=1;
            dfs(i+1,tw+w[i],tv+v[i],op);
        }
        op[i]=0;
        dfs(i+1,tw,tv,op);
    }
}
int main()
{
    scanf("%d %d",&n,&W);
    for(int i=1;i<=n;i++) scanf("%d %d",&w[i],&v[i]);
    dfs(1,0,0,op);
    for(int i=1;i<=n;i++) if(x[i]) t++,cout<<i<<" ";
    if(!t) printf("No");
    printf("\n%d",maxv);
    return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值