0-1背包问题与N皇后问题的纠结

昨日同学要我帮他看一道算法,如下:


是不是乍一看是“0-1背包”问题呀,我也这么想,于是就这么兴致勃勃的开始用这个想法去思考怎么算。但是算法也忘得差不多,回去赶紧补补,也趁着这次机会好好复习一下算法,于是觉得“0-1背包”问题实现了,这个问题也差不多了吧:

/***********************0-1背包*************************************/

 1 //先将那两个条件忽略,单纯利用动态规划 -------------------这里就看出有多傻-—_--
 2 //利用动态规划求解
 3 #include <iostream>
 4 #define MAX_NUM 50
 5 #define MAX_WEIGHT 100
 6 using namespace std;
 7
 8 //动态规划求解
 9 int zero_one_pack(int total_weight, int w[], int v[], int flag[], int n) {
10     int c[MAX_NUM + 1][MAX_WEIGHT + 1] = { 0 }; //c[i][j]表示前i个物体放入容量为j的背包获得的最大价值
11     // c[i][j] = max{c[i-1][j], c[i-1][j-w[i]]+v[i]}
12     //第i件物品要么放,要么不放
13     //如果第i件物品不放的话,就相当于求前i-1件物体放入容量为j的背包获得的最大价值
14     //如果第i件物品放进去的话,就相当于求前i-1件物体放入容量为j-w[i]的背包获得的最大价值
15     for (int i = 1; i <= n; i++) {
16         for (int j = 1; j <= total_weight; j++) {
17             if (w[i] > j ) {
18                 // 说明第i件物品大于背包的重量,放不进去
19                 c[i][j] = c[i - 1][j];
20             }
21
22             else {
23                 //说明第i件物品的重量小于背包的重量,所以可以选择第i件物品放还是不放
24                 if (c[i - 1][j] > v[i] + c[i - 1][j - w[i]]) {
25                     c[i][j] = c[i - 1][j];
26                 }
27                 else {
28                     c[i][j] = v[i] + c[i - 1][j - w[i]];
29                 }
30             }
31         }
32     }
33
34     //下面求解哪个物品应该放进背包
35     int i = n, j = total_weight;
36     while (c[i][j] != 0) {
37         if (c[i - 1][j - w[i]] + v[i] == c[i][j]) {
38             // 如果第i个物体在背包,那么显然去掉这个物品之后,前面i-1个物体在重量为j-w[i]的背包下价值是最大的
39             flag[i] = 1;
40             j -= w[i];
41         }
42         --i;
43     }
44     return c[n][total_weight];
45 }
46
47 //回溯法求解
48
49 int main() {
50     int total_weight = 60;
51     int w[7] = { 0,7, 10, 4, 9, 3,6 };
52     int v[7] = { 0,4, 5, 2, 3, 1 ,2};
53     int flag[7]; //flag[i][j]表示在容量为j的时候是否将第i件物品放入背包
54     int total_value = zero_one_pack(total_weight, w, v, flag, 6);
55     cout << "需要放入的物品如下" << endl;
56     for (int i = 1; i <= 6; i++) {
57         if (flag[i] == 1)
58             cout << i << "重量为" << w[i] << ", 价值为" << v[i] << endl;
59     }
60     cout << "总的价值为: " << total_value << endl;
61     system("pause");
62     return 0;
63 }

查看一下结果,


卧槽,瞎了。背包值这么大原来!于是乎还是想着如何利用“0-1背包”解决,但越想越不对劲,要让程序记住所有路径然后根据条件进行筛选,发现是在太过于复杂。但什么算法可以呢,于是想到了N皇后问题,介于设置的最大载重量太大,不具代表性,于是大大减少最大载重量,设计一下,行表示要存放的对象,列用1,0表示是否要放入,利用不断的回溯递归取得所有可能的值,再选择最大值:


/***********************N皇后*****************************************/

  1 #include <iostream>
  2 using namespace std;
  3
  4 int total_weight = 35; //修改最大值
  5 int w[7] = { 0, 7, 10, 4, 9, 3, 6 };
  6 int v[7] = { 0, 4, 5, 2, 3, 1, 2 };
  7 int result[7] = { 0 };
  8 int result_all[10][7] ;//用于存储所有的可能结果
  9 int indi = 0; //结果指针
 10 int num = 6;
 11
 12
 13 int sumV();
 14 int sumW(int n);
 15
 16 //判断下一个是否符合条件
 17 bool judge(int n)
 18 {
 19     if (n == 4)
 20     {
 21         if (result[4] >= result[1])
 22             return true;
 23         else
 24             return false;
 25
 26     }
 27     if (n == 5)
 28     {
 29         if ((result[5] + result[3]) == 1)
 30             return true;
 31         else
 32             return false;
 33     }
 34
 35     if (sumW(n) > total_weight)
 36         return false;
 37     return true;
 38 }
 39
 40 //主要的递归调用函数
 41 void backtrack(int n)
 42 {
 43     if (n > num)
 44
 45     {
 46
 47         for (int i = 1; i <= num; i++)
 48         {
 49             result_all[indi][i] = result[i];
 50         }
 51         indi++;
 52     }
 53
 54     else
 55     {
 56         for (int i = 1; i >= 0; i--)
 57         {
 58             result[n] = i;
 59             if (judge(n))
 60                 backtrack(n+1);
 61         }
 62     }
 63 }
 64
 65 //计算综价值
 66 int sumV(  )
 67 {
 68     int m = 0;
 69     for (int i = 1; i <= num; i++)
 70     {
 71         if (result[i] == 1)
 72             m += v[i];
 73     }
 74     return m;
 75 }
 76 //计算重量
 77 int sumW(int n)
 78 {
 79     int m = 0;
 80     for (int i = 1; i <= n; i++)
 81     {
 82         if (result[i] == 1)
 83             m += w[i];
 84     }
 85     return m;
 86 }
 87
 88 int main()
 89 {
 90     backtrack(1);
 91
 92     //计算最大值
 93     int most = 0;
 94     int pos = 0;
 95     for (int i = 0; i < indi; i++)
 96     {
 97         int temp = 0;
 98         for (int j = 1; j <= num; j++)
 99         {
100             if (result_all[i][j] == 1)
101                 temp += v[j];
102         }
103         if (temp>most)
104         {
105             most = temp;
106             pos = i;
107
108         }
109     }
110
111     cout << "最大值是:"<<most<<endl;
112     cout << "结果是:" << endl;
113     for (int i = 1; i <= num; i++)
114     {
115         cout << result_all[pos][i]<<"   ";
116     }
117     cout << endl;
118     system("pause");
119 }

结果:


所以说啊,算法死记硬背是没啥用的,还得看具体情况来,算法还得多学,这次教训大了。

时间: 2024-10-14 03:15:23

0-1背包问题与N皇后问题的纠结的相关文章

背包问题:0/1背包问题 普通背包问题(贪心算法只适用于普通背包问题)

//sj和vj分别为第j项物品的体积和价值,W是总体积限制. //V[i,j]表示从前i项{u1,u2,…,un}中取出来的装入体积为j的背包的物品的最大价值. 第一种:0/1背包问题 最大化 ,受限于  1)若i=0或j=0,  V[i,j] = 0 2)若j<si, V[i,j] = V[i-1,j] 3)若i>0且j>=si, V[i,j] = Max{V[i-1,j],V[i-1,j-si]+vi} 第二种:背包问题:在选择物品i装入背包时,可以选择物品i的一部分,而不一定要全部

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

回溯法是一个既带有系统性又带有跳跃性的搜索算法.它在包含问题的所有解的解空间树中,按深度优先策略,从根结点出发搜索解空间树.算法搜索至解空间树的任意一结点时,先判断该结点是否包含问题的解.如果肯定不包含,则跳过对该结点为根的子树搜索,逐层向其祖先结点回溯:否则 ,进入该子树,继续按深度优先策略搜索. 问题的解空间 用回溯法解问题时,应明确定义问题的解空间.问题的解空间至少包含问题的一个(最优)解.对于 n=3 时的 0/1 背包问题,可用一棵完全二叉树表示解空间,如图所示: 求解步骤 1)针对所

0/1背包问题的动态规划法求解 —— Java 实现

0/1背包问题的动态规划法求解,前人之述备矣,这里所做的工作,不过是自己根据理解实现了一遍,主要目的还是锻炼思维和编程能力,同时,也是为了增进对动态规划法机制的理解和掌握. 值得提及的一个问题是,在用 JAVA 实现时, 是按算法模型建模,还是用对象模型建模呢? 如果用算法模型,那么 背包的值.重量就直接存入二个数组里:如果用对象模型,则要对背包以及背包问题进行对象建模.思来想去,还是采用了对象模型,尽管心里感觉算法模型似乎更好一些.有时确实就是这样,对象模型虽然现在很主流,但也不是万能的,采用

动态规划算法实现部分——0/1背包问题

代码: import java.util.*; import java.util.Scanner; /* *动态规划思想解决0/1背包问题 */ public class Main{ public static void main(String[] args){ Scanner in=new Scanner(System.in); System.out.println("输入背包的容量"); int bagCap=in.nextInt(); //背包的容量 System.out.pri

动态规划算法求解0,1背包问题

首先我们来看看动态规划的四个步骤: 1. 找出最优解的性质,并且刻画其结构特性: 2. 递归的定义最优解: 3. 以自底向上的方式刻画最优值: 4. 根据计算最优值时候得到的信息,构造最优解 其中改进的动态规划算法:备忘录法,是以自顶向下的方式刻画最优值,对于动态规划方法和备忘录方法,两者的使用情况如下: 一般来讲,当一个问题的所有子问题都至少要解一次时,使用动态规划算法比使用备忘录方法好.此时,动态规划算法没有任何多余的计算.同时,对于许多问题,常常可以利用其规则的表格存取方式,减少动态规划算

动态规划0—1背包问题

动态规划0-1背包问题 ? 问题描写叙述: 给定n种物品和一背包.物品i的重量是wi,其价值为vi,背包的容量为C.问应怎样选择装入背包的物品,使得装 入背包中物品的总价值最大? ? 对于一种物品,要么装入背包,要么不装.所以对于一种物品的装入状态能够取0和1.我们设物品i的装入状态为xi,xi∈ (0,1),此问题称为0-11背包问题. 过程分析 数据:物品个数n=5,物品重量w[n]={0,2,2,6,5,4},物品价值V[n]={0,6,3,5,4,6}, (第0位,置为0,不參与计算,仅

【算法设计与分析】7、0/1背包问题,动态规划

/** * 书本:<算法分析与设计> * 功能:给定n种物品和一个背包,物品i的重量是Wi, 其价值为Vi,问如何选择装入背包的物品,使得装入背包的物品的总价值最大? * 文件:beiBao.cpp * 时间:2014年11月30日19:22:47 * 作者:cutter_point */ #include <iostream> #define SIZEBEIBAO 20 using namespace std; //这个背包问题的最优的子结构是 /* 首先这里一共有m种物品,背包

第十六章 贪心算法——0/1背包问题

1.问题描述: 给定n种物品和一背包.物品i的重量是wi,其价值为vi,背包的容量为C.问:应如何选择装入背包的物品,使得装入背包中物品的总价值最大? 形式化描述:给定c >0, wi >0, vi >0 , 1≤i≤n.要求找一n元向量(x1,x2,…,xn,), xi∈{0,1}, ∋ ∑ wi xi≤c,且∑ vi xi达最大.即一个特殊的整数规划问题. 2.最优性原理: 设(y1,y2,…,yn)是 (3.4.1)的一个最优解.则(y2,…,yn)是下面相应子问题的一个最优解:

动态规划--0,1背包问题(再也不怕类似背包问题了)

这种类型问题三大要素:总重量.每件物品重量.每件物品价值,问最终能够塞进背包中的价值最大是多少?应该怎么选择物品? 当然也不一定是这些,例如上节所说的矿工挖矿:总人数.挖每座矿的人数.每座矿的金子数. 也就是说,只要出现了这三大要素,都可以视为0,1背包问题(物品不可拆分) 动态规划三要素:边界.最优子结构.状态转移方程. 我们一步步进行解析: 初始化:物品总重量:c=8,物品类别:n=['a','b','c','d'],物品重量:w=[2,4,5,3],物品价值:v=[5,4,6,2] 假设我