- 数据结构与算法
- DSA - 首页
- DSA - 概述
- DSA - 环境设置
- DSA - 算法基础
- DSA - 渐进分析
- 数据结构
- DSA - 数据结构基础
- DSA - 数据结构和类型
- DSA - 数组数据结构
- 链表
- DSA - 链表数据结构
- DSA - 双向链表数据结构
- DSA - 循环链表数据结构
- 栈与队列
- DSA - 栈数据结构
- DSA - 表达式解析
- DSA - 队列数据结构
- 搜索算法
- DSA - 搜索算法
- DSA - 线性搜索算法
- DSA - 二分搜索算法
- DSA - 插值搜索
- DSA - 跳跃搜索算法
- DSA - 指数搜索
- DSA - 斐波那契搜索
- DSA - 子列表搜索
- DSA - 哈希表
- 排序算法
- DSA - 排序算法
- DSA - 冒泡排序算法
- DSA - 插入排序算法
- DSA - 选择排序算法
- DSA - 归并排序算法
- DSA - 希尔排序算法
- DSA - 堆排序
- DSA - 桶排序算法
- DSA - 计数排序算法
- DSA - 基数排序算法
- DSA - 快速排序算法
- 图数据结构
- DSA - 图数据结构
- DSA - 深度优先遍历
- DSA - 广度优先遍历
- DSA - 生成树
- 树数据结构
- DSA - 树数据结构
- DSA - 树遍历
- DSA - 二叉搜索树
- DSA - AVL树
- DSA - 红黑树
- DSA - B树
- DSA - B+树
- DSA - 伸展树
- DSA - 字典树
- DSA - 堆数据结构
- 递归
- DSA - 递归算法
- DSA - 使用递归实现汉诺塔
- DSA - 使用递归实现斐波那契数列
- 分治法
- DSA - 分治法
- DSA - 最大最小值问题
- DSA - Strassen矩阵乘法
- DSA - Karatsuba算法
- 贪心算法
- DSA - 贪心算法
- DSA - 旅行商问题(贪心法)
- DSA - Prim最小生成树
- DSA - Kruskal最小生成树
- DSA - Dijkstra最短路径算法
- DSA - 地图着色算法
- DSA - 分数背包问题
- DSA - 带截止期限的作业排序
- DSA - 最优合并模式算法
- 动态规划
- DSA - 动态规划
- DSA - 矩阵链乘法
- DSA - Floyd-Warshall算法
- DSA - 0-1背包问题
- DSA - 最长公共子序列算法
- DSA - 旅行商问题(动态规划法)
- 近似算法
- DSA - 近似算法
- DSA - 顶点覆盖算法
- DSA - 集合覆盖问题
- DSA - 旅行商问题(近似算法)
- 随机化算法
- DSA - 随机化算法
- DSA - 随机化快速排序算法
- DSA - Karger最小割算法
- DSA - Fisher-Yates洗牌算法
- DSA有用资源
- DSA - 问答
- DSA - 快速指南
- DSA - 有用资源
- DSA - 讨论
拔河问题
什么是拔河问题?
在拔河问题中,给定一组整数,我们的任务是将它们分成两部分,使得两个子集的和的差尽可能小。换句话说,将集合分成两个实力大致相等的组,以参加拔河比赛。当集合大小为偶数时,将其分成两部分更容易。用奇数个项目这样做会比较困难。因此,对划分有一些定义的约束。
如果子集N的大小为偶数,可以使用N/2将其分成两部分,但对于奇数N,一个子集的大小必须为(N-1)/2,另一个子集的大小必须为(N+1)/2。
使用回溯法解决拔河问题
假设给定的集合大小为奇数:
Set = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4}
当我们分配权重以使差异最小化时,结果子集将是:
Left: {45, -34, 12, 98, -1} Right: {23, 0, -99, 4, 189, 4}
以下步骤解释了如何使用回溯法来解决拔河问题:
首先创建一个空子集,称为左子集。
用原始集合中所需数量的元素填充这个空子集。所需元素的数量取决于原始集合的大小。如果大小为奇数,则子集应填充 (N-1)/2 个元素;如果大小为偶数,则子集的大小应为 N/2。
检查填充元素的差是否遵循给定的约束条件。如果遵循,则将其标记为解决方案的一部分。
如果差异不是最小值,则尝试其他组合并更新现有解决方案。
一旦第一个子集被填充,其余元素将自动成为第二个子集的一部分。
示例
在下面的示例中,我们将实际演示如何解决拔河问题。
#include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <limits.h> #include <math.h> void tgOfWarSoln(int* weight, int n, bool curr[], int select, bool sol[], int *diff, int sum, int total, int pos) { //when the pos is covered all weights if (pos == n) return; //left elements must be bigger than required result if ((n/2 - select) > (n - pos)) return; tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1); select++; total += weight[pos]; //add current element to the solution curr[pos] = true; //when solution is formed if (select == n/2) { //check whether it is better solution or not if (abs(sum/2 - total) < *diff) { *diff = abs(sum/2 - total); for (int i = 0; i<n; i++) sol[i] = curr[i]; } } else { tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1); } //when not properly done, remove current element curr[pos] = false; } void checkSolution(int *arr, int n) { bool* curr = (bool*)malloc(n*sizeof(bool)); bool* soln = (bool*)malloc(n*sizeof(bool)); //set minimum difference to infinity initially int diff = INT_MAX; int sum = 0; for (int i=0; i<n; i++) { //find the sum of all elements sum += arr[i]; //make all elements as false curr[i] = soln[i] = false; } tgOfWarSoln(arr, n, curr, 0, soln, &diff, sum, 0, 0); printf("Left: "); for (int i=0; i<n; i++) if (soln[i] == true) printf("%d ", arr[i]); printf("\nRight: "); for (int i=0; i<n; i++) if (soln[i] == false) printf("%d ", arr[i]); printf("\n"); free(curr); free(soln); } int main() { int weight[] = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4}; int n = 11; checkSolution(weight, n); return 0; }
#include <iostream> #include <cmath> #include <climits> using namespace std; void tgOfWarSoln(int* weight, int n, bool curr[], int select, bool sol[], int &diff, int sum, int total, int pos) { //when the pos is covered all weights if (pos == n) return; //left elements must be bigger than required result if ((n/2 - select) > (n - pos)) return; tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1); select++; total += weight[pos]; //add current element to the solution curr[pos] = true; //when solution is formed if (select == n/2) { //check whether it is better solution or not if (abs(sum/2 - total) < diff) { diff = abs(sum/2 - total); for (int i = 0; i<n; i++) sol[i] = curr[i]; } } else { tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos+1); } //when not properly done, remove current element curr[pos] = false; } void checkSolution(int *arr, int n) { bool* curr = new bool[n]; bool* soln = new bool[n]; //set minimum difference to infinity initially int diff = INT_MAX; int sum = 0; for (int i=0; i<n; i++) { //find the sum of all elements sum += arr[i]; //make all elements as false curr[i] = soln[i] = false; } tgOfWarSoln(arr, n, curr, 0, soln, diff, sum, 0, 0); cout << "Left: "; for (int i=0; i<n; i++) if (soln[i] == true) cout << arr[i] << " "; cout << endl << "Right: "; for (int i=0; i<n; i++) if (soln[i] == false) cout << arr[i] << " "; } int main() { int weight[] = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4}; int n = 11; checkSolution(weight, n); }
public class Main { static void tgOfWarSoln(int[] weight, int n, boolean[] curr, int select, boolean[] sol, int[] diff, int sum, int total, int pos) { //when the pos is covered all weights if (pos == n) return; //left elements must be bigger than required result if ((n / 2 - select) > (n - pos)) return; tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1); select++; //add current element to the solution total += weight[pos]; curr[pos] = true; //when solution is formed if (select == n / 2) { //check whether it is better solution or not if (Math.abs(sum / 2 - total) < diff[0]) { diff[0] = Math.abs(sum / 2 - total); for (int i = 0; i < n; i++) sol[i] = curr[i]; } } else { tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1); } //when not properly done, remove current element curr[pos] = false; } static void checkSolution(int[] arr, int n) { boolean[] curr = new boolean[n]; boolean[] soln = new boolean[n]; //set minimum difference to infinity initially int[] diff = {Integer.MAX_VALUE}; int sum = 0; for (int i = 0; i < n; i++) { //find the sum of all elements sum += arr[i]; //make all elements as false curr[i] = soln[i] = false; } tgOfWarSoln(arr, n, curr, 0, soln, diff, sum, 0, 0); System.out.print("Left: "); for (int i = 0; i < n; i++) if (soln[i] == true) System.out.print(arr[i] + " "); System.out.println(); System.out.print("Right: "); for (int i = 0; i < n; i++) if (soln[i] == false) System.out.print(arr[i] + " "); } public static void main(String[] args) { int[] weight = {23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4}; int n = 11; checkSolution(weight, n); } }
def tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos): if pos == n: return if (n // 2 - select) > (n - pos): return tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1) select += 1 total += weight[pos] curr[pos] = True if select == n // 2: if abs(sum // 2 - total) < diff[0]: diff[0] = abs(sum // 2 - total) for i in range(n): sol[i] = curr[i] else: tgOfWarSoln(weight, n, curr, select, sol, diff, sum, total, pos + 1) curr[pos] = False def checkSolution(arr, n): curr = [False] * n soln = [False] * n diff = [float('inf')] sum = 0 for i in range(n): sum += arr[i] curr[i] = soln[i] = False tgOfWarSoln(arr, n, curr, 0, soln, diff, sum, 0, 0) print("Left: ", end="") for i in range(n): if soln[i] == True: print(arr[i], end=" ") print() print("Right: ", end="") for i in range(n): if soln[i] == False: print(arr[i], end=" ") weight = [23, 45, -34, 12, 0, 98, -99, 4, 189, -1, 4] n = 11 checkSolution(weight, n)
输出
Left: 45 -34 12 98 -1 Right: 23 0 -99 4 189 4
广告