算法设计与分析-习题12.2

目录

1.在一个最佳优先分支界限算法中,我们应该使用什么样的数据结构来跟踪活节点?

2.对于本节求解的分配问题的相同实例,用基于矩阵列(而不是行)的边界函数以及最佳优先分支界限算法求解。

3.

a.对于分配问题的分支界限算法,给出一个最优输入的例子。

b.对于分配问题的分支界限算法来说,在最好的情况下,它的状态空间树会包含多少节点?

5.用分支界限算法对背包问题的以下实例求解。

6.

a.对于背包问题,给出一个比本节介绍的更复杂(也更好)的边界函数。

b.根据这个边界函数,用分支界限算法对第5题的实例求解。

7.写一个程序用分支界限算法对背包问题求解。

8.

a.在旅行商问题的实例中,如果用整数对称矩阵表示城市间的距离,请证明公式(12.2)给出的下界的合法性。

b.对于非对称距离矩阵,我们应该如何修改下界公式(12.2)?

9.对于下面的图,应用分支界限算法求解旅行商问题。


1.在一个最佳优先分支界限算法中,我们应该使用什么样的数据结构来跟踪活节点?

堆和最小堆分别用于最大化和最小化问题。

2.对于本节求解的分配问题的相同实例,用基于矩阵列(而不是行)的边界函数以及最佳优先分支界限算法求解。

3.

a.对于分配问题的分支界限算法,给出一个最优输入的例子。

矩阵的每个值都相同的时候

b.对于分配问题的分支界限算法来说,在最好的情况下,它的状态空间树会包含多少节点?

最好的时候,每一层都剪枝,只留一条路,那么第一层n个,第二层n-1个,最后一层1个

所以最好情况节点数 = n (n+1)/2

5.用分支界限算法对背包问题的以下实例求解。

计算分别的单个价值为:10、9、7、3

因此有初始根节点是16*10=160,确定下界,确定取1的情况下,W=6,此时有6*9+100=154,此时选2超重,再选3也超重,最后选4界为100+6*3=118,W=2。

而不选1的情况下,选2的界为16*9=144,此时选2,W=9,v=63,选3时界63+63=126,此时选3,W=1,v=63+56=119,选4则超重;若不选3,选4界为63+27=90,此时选4则W=5,v=75

不选2时,选3的界为112,此时选3,W=8,v=56,选4时界为56+32=88,此时选4为W=4,56+12=68

最终发现最近方案为2,3,v=119

6.

a.对于背包问题,给出一个比本节介绍的更复杂(也更好)的边界函数。

改进的上界函数:

  1. 单位重量价值降序排序物品
  2. 尽可能装满整数物品
  3. 最后装一部分下一个物品填满背包
  4. 得到最紧的上界(比原来大很多,剪枝更强)

b.根据这个边界函数,用分支界限算法对第5题的实例求解。

排序后:

复制代码
1: w=10, v=100, 单价 10
2: w=7, v=63, 单价 9
3: w=8, v=56, 单价 7
4: w=4, v=12, 单价 3
容量 W=16
  1. 根节点(没选任何物品)
  • 当前重量 = 0,当前价值 = 0
  • 剩余容量 = 16

计算最优上界:

  • 装物品 1(w=10)→ 剩余 6
  • 装物品 2(w=7)装不下,装物品 3(w=8)装不下
  • 装物品 4 一部分:6×3=18

bound = 100 + 18 = 118


  1. 左分支:选物品 1
  • 重量 = 10,价值 = 100
  • 剩余 = 6

计算上界:

  • 物品 2(w=7)装不下
  • 物品 3(w=8)装不下
  • 物品 4 可全装(w=4)→ 价值 + 12
  • 剩余 2,无物品可装

bound = 100 + 12 = 112

这是可行解选 1+4,价值 112,重量 14


  1. 右分支:不选物品 1
  • 重量 = 0,价值 = 0
  • 剩余 = 16

计算上界:

  • 装物品 2(w=7)→ 剩余 9
  • 装物品 3(w=8)→ 剩余 1
  • 装物品 4 一部分:1×3=3

bound = 63+56+3 = 122(虽然上界高,但实际最大只能到 63+56=119 <112?不:119>112,继续)

继续搜索后,最大可行解:物品 2+3=119 (重量 15)物品 2+4=75 物品 3+4=68

最大为 119

7.写一个程序用分支界限算法对背包问题求解。

复制代码
#include <stdio.h>
#include <stdlib.h>

// 物品结构体
typedef struct {
    int w;      // 重量
    int v;      // 价值
    double cp;  // 单位价值
} Item;

// 队列节点(分支界限用)
typedef struct Node {
    int level;      // 当前层数(第几个物品)
    int weight;     // 当前总重量
    int value;      // 当前总价值
    double bound;   // 上界
} Node;

Item items[100];
int n, W;          // 物品数、背包容量
int maxValue = 0;  // 最优价值

// 按单位价值降序排序
int cmp(const void *a, const void *b) {
    Item *i1 = (Item *)a;
    Item *i2 = (Item *)b;
    if (i1->cp < i2->cp) return 1;
    return -1;
}

// 计算上界(第6题的最优边界:先装完整物品,再装分数)
double bound(Node u) {
    if (u.weight >= W) return 0;

    double res = u.value;
    int totW = u.weight;
    int i = u.level;

    // 先装能装下的完整物品
    while (i < n && totW + items[i].w <= W) {
        totW += items[i].w;
        res += items[i].v;
        i++;
    }
    // 再装分数物品
    if (i < n) {
        res += items[i].cp * (W - totW);
    }
    return res;
}

// 分支界限核心算法
void knapsack() {
    Node q[1000];  // 队列
    int front = 0, rear = 0;

    // 根节点
    Node root;
    root.level = 0;
    root.weight = 0;
    root.value = 0;
    root.bound = bound(root);
    q[rear++] = root;

    while (front < rear) {
        Node cur = q[front++];

        // 更新最优解
        if (cur.value > maxValue)
            maxValue = cur.value;

        // 到达最后一层,不扩展
        if (cur.level == n) continue;

        // 上界 <= 当前最优,剪枝
        if (cur.bound <= maxValue) continue;

        // ====================== 左孩子:选当前物品 ======================
        Node left;
        left.level = cur.level + 1;
        left.weight = cur.weight + items[cur.level].w;
        left.value = cur.value + items[cur.level].v;

        if (left.weight <= W && left.value > maxValue) {
            left.bound = bound(left);
            q[rear++] = left;
        }

        // ====================== 右孩子:不选当前物品 ====================
        Node right;
        right.level = cur.level + 1;
        right.weight = cur.weight;
        right.value = cur.value;
        right.bound = bound(right);

        if (right.bound > maxValue) {
            q[rear++] = right;
        }
    }
}

int main() {
    // 第5题数据
    n = 4;
    W = 16;
    items[0] = (Item){10, 100, 100 / 10.0};
    items[1] = (Item){7, 63, 63 / 7.0};
    items[2] = (Item){8, 56, 56 / 8.0};
    items[3] = (Item){4, 12, 12 / 4.0};

    // 按单位价值排序
    qsort(items, n, sizeof(Item), cmp);

    maxValue = 0;
    knapsack();

    printf("背包容量 W = %d\n", W);
    printf("最优总价值 = %d\n", maxValue);
    return 0;
}

8.

a.在旅行商问题的实例中,如果用整数对称矩阵表示城市间的距离,请证明公式(12.2)给出的下界的合法性。

  • 任何 TSP 回路,每个城市恰好使用两条边
  • 对每个城市,回路中它的两条边之和≥ 该城市最小两条边之和。
  • 对所有城市求和:∑i=1n(回路中i的两条边)≥s
  • 左边每条边在回路中被两个端点各算一次,所以2L≥s
  • 因此:L≥2s
  • 因为 L 是整数,所以最小可能的整数上界就是L≥⌈2s⌉

b.对于非对称距离矩阵,我们应该如何修改下界公式(12.2)?

  • 每条有向边只被计算一次,不会在两个方向重复计入 s

所以不再除以 2,直接用:lb=s

9.对于下面的图,应用分支界限算法求解旅行商问题。

先走ab

然后走ac,发现b没在c前,舍弃

再在ab的基础上选:cda或者dca

得出结果:

得出路径为abdca,l=11

相关推荐
江畔柳前堤7 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore8 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考10 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX10 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面11 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号11 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽11 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI11 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者13 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者13 小时前
【征程6】校准量化中HistogramObserver解析
算法