当前位置: 首页 > ai >正文

0-1背包问题(回溯法c++详解)

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

题目描述

有n个物品,第i个物品重量为wi,价值为vi,现有一背包容量为C,要求把物品装入背包得到最大价值,并且要求出这些选取的物品。 要求用回溯法求解。

输入

多组测试数据,请处理到文件尾,一个整数表示物品的数量n,后一行有n个整数,代表价值,再后一行有n个整数,代表重量,最后有一个整数C代表背包容量,1<=n<=15,1<=vi<=30,1<=wi<=30,1<=C<=80。

输出

背包的最大总价值和所选取的物品,如果选取的方案有多种,请输出字典序最小的那种方案,每组测试数据应输出一行,在这里字典序最小的意思是,我们假设存在两种不同方案S,T所能得到的总价值相同且是最大的,对于方案S种选取|S|种物品,方案T选取|T|种物品,对于i=1,2...j-1,我们有si = ti,但sj < tj,则方案的S的字典序比方案T的字典序要小。由于没有使用special judge,所以如果选取得方案是S,请按照从小到大的顺序输出方案S中的物品下标。

样例输入 Copy

5
6 3 6 5 4
2 2 4 6 5
8

样例输出 Copy

15 1 2 3

 我不信注释都这么详细了还能够看不懂!!!!!!

#include<iostream>
#include<math.h>
#include<string>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
int n,C;
int w[20],v[20];//背包中各个数的重量和价值int best_ans[20],ans[20];//最优解和当前解 ,判断背包中各个数是否被装入
int wsum,vsum,mvsum;//当前已选背包中的重量和价值、最大价值 void dfs(int t,int ww,int vv){//这里传入当前的背包剩余容量和价值,是为了维护当前这个价值 if(t>n){//大于n时表示已经找到了一组解 if(vsum>mvsum){mvsum=vsum;for(int i=1;i<=n;i++)best_ans[i]=ans[i];//替换最优值的选取方法 }else if(vsum==mvsum){for(int i=1;i<=n;i++){if(best_ans[i]>ans[i])//如果字典序比当前的字典序大,则保留字典序小的 {for(int j=1;j<=n;j++)best_ans[i]=ans[i];break;}		}} }else{//否则继续判断int temp=vsum;//这里是一个剪枝,也是我认为比较精妙的地方for(int i=t;i<=n;i++)temp+=v[i];//这个是为了判断到了当前这个地方的时候直接把后面的所有价值相加与最优价值相比较,如果比最优价值小那么这一组解就没有必要继续回溯下去了 if(temp<mvsum)return;if(wsum>=w[t]){//如果还能够装入下一个物品 wsum-=w[t];vsum+=v[t];ans[t]=1;//标记已经放入	dfs(t+1,wsum,vsum);//继续搜索下一个ans[t]=0;//切记回溯后得回归原来的位置 wsum+=w[t];vsum-=v[t]; } dfs(t+1,wsum,vsum); }
}int main(){while(cin>>n){memset(ans,0,20);memset(best_ans,0,20);//每次都要初始化for(int i=1;i<=n;i++)cin>>v[i];//价值for(int i=1;i<=n;i++)cin>>w[i];//重量cin>>C;//总容量wsum=C,vsum=0,mvsum=0;dfs(1,wsum,vsum); cout<<mvsum;for(int i=1;i<=n;i++){if(best_ans[i]==1)cout<<" "<<i;}cout<<endl;}return 0;
} 

N皇后问题 

题目描述

使用回溯法求解N后问题。

输入

皇后的个数。

输出

每一种方案及总方案数。

样例输入 Copy

4

样例输出 Copy

0 1 0 0
0 0 0 2
3 0 0 0
0 0 4 0
----------------
0 0 1 0
2 0 0 0
0 0 0 3
0 4 0 0
----------------
总方案数为:2

 本题详解可以看我这一篇文章

#include<bits/stdc++.h>
using namespace std;
int sum=0;
int mm[1005][1005];
int x[1005];//x[i]表示第i行在x[i]列 
int n;
int isright(int t){
    for(int i=1;i<t;i++){
        if((abs(t-i)==abs(x[t]-x[i]))||x[t]==x[i])return 0;//判断是否满足条件
    }
    return 1;
}
 
void queen(int k){
    if(k>n){//行数为k,当k大于n时有解了
        sum++;//方案数加1
        for(int i=1;i<=n;i++){//把每一行的皇后的位置赋值给mm数组中的同一行列值
            mm[i][x[i]]=i;
        }
        for(int i=1;i<=n;i++)//输出数组
        for(int j=1;j<=n;j++){
            if(j!=n)cout<<mm[i][j]<<" ";
            else cout<<mm[i][j]<<endl;
        }
        memset(mm,0,sizeof(mm));//一定要记得清空数组,因为如果有多组解那么他会造成上一组的解仍然保留
        //cout<<endl;
        cout<<"----------------"<<endl;
    }
    
    else
    for (int i = 1; i <= n; i++)
    {
        x[k] = i;
        if (isright(k))//如果当前行满足条件则判断下一行
        queen(k + 1);//回溯
    }

int main(){
    
    cin>>n;
    queen(1);//从第一行开始判断
    cout<<"总方案数为:"<<sum<<endl;
    return 0;
}

http://www.xdnf.cn/news/11710.html

相关文章:

  • STM32外部挂载SDcard+移植Fatfs文件系统
  • tl r402路由器设置_tplogin.cn登录路由器怎么设置 tplogin.cn登录路由器设置步骤【详解】...
  • Android光线传感器获取光线强弱。LightSensorManager封装类
  • position的relative与absolute的区别
  • 非线性丙类功率放大器实验_倾斜光纤Bragg光栅:抑制高功率光纤激光系统SRS和SBS的理想选择...
  • 网安学习日志01:用kali复现ms17-010漏洞
  • 传奇私服游戏支付接口申请(已解决)
  • iTunes 9.0.3 更新
  • Linux系统服务之inetd
  • 445端口入侵详解
  • 用 Java 实现“人像动漫化”特效
  • Windows 安全基础——NetBIOS篇
  • 硬盘模式JBOD
  • C++实现银行家算法
  • 应用程序发生异常--未知的软件异常怎么办?
  • 【Android动画入门篇】
  • 寄存器分配图着色_着色基础------抗锯齿与半透明
  • Adobe Acrobat pro 9.0 序列号
  • 【硬核】优质 嵌入式C编程 必备指南
  • 张老师的生日究竟是哪天(经典推理题[转载])
  • php core,分析php core dump的原因
  • Unity3D入门基础知识汇总
  • 在线免费生成IntelliJ IDEA 15.0(16.+)注册码
  • tab切换之图片切换
  • a标签点击中文文件名乱码,通过a标签href属性跳转后台乱码问题
  • 电子合同签署平台有哪些?2024年靠谱10家对比
  • 深入剖析《开端》是如何找到引爆凶手的?
  • 802.11n无线网卡驱动linux,安装Broadcom Linux hybrid 无线网卡驱动总结
  • Visual Studio 11开发指南(1) Visual Studio 11简介与新特性
  • 微博明星事件421整合文档