diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6c13913 --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +*.exe +.vscode/* +template/* +*.zip +*/datas/* \ No newline at end of file diff --git a/1/data.in b/1/data.in new file mode 100644 index 0000000..9742b21 --- /dev/null +++ b/1/data.in @@ -0,0 +1,3 @@ +10 +6 +1 8 4 3 5 2 \ No newline at end of file diff --git a/1/data.out b/1/data.out new file mode 100644 index 0000000..d1f5072 --- /dev/null +++ b/1/data.out @@ -0,0 +1,5 @@ +1 4 3 2 +1 4 5 +8 2 +3 5 2 +4 diff --git a/1/make_data.py b/1/make_data.py new file mode 100644 index 0000000..e6e7ccf --- /dev/null +++ b/1/make_data.py @@ -0,0 +1,37 @@ +from cyaron import * # 引入CYaRon的库 + +T = 1000 +n = 100 +w = [] + + +for i in range(10): + test_data = IO(file_prefix="./datas/t1_", data_id=i+1) + T = 10 + n = randint(1, 10) + w = [randint(1, 4) for i in range(n)] + test_data.input_writeln(T) + test_data.input_writeln(n) + test_data.input_writeln(w) + test_data.output_gen("solution1.exe") + +for i in range(10): + test_data = IO(file_prefix="./datas/t1_", data_id=i+11) + T = 30 + n = randint(6, 10) + w = [randint(1, 10) for i in range(n)] + test_data.input_writeln(T) + test_data.input_writeln(n) + test_data.input_writeln(w) + test_data.output_gen("solution1.exe") + + +for i in range(10): + test_data = IO(file_prefix="./datas/t1_", data_id=i+21) + T = 50 + n = randint(15, 35) + w = [randint(1, 4) for i in range(n)] + test_data.input_writeln(T) + test_data.input_writeln(n) + test_data.input_writeln(w) + test_data.output_gen("solution1.exe") diff --git a/1/problem.md b/1/problem.md new file mode 100644 index 0000000..26bb248 --- /dev/null +++ b/1/problem.md @@ -0,0 +1,15 @@ +## 问题描述 +假设有一个能装入总体积为`T`的背包和`n`件体积分别为`w1,w2,…wn`的物品,能否从`n`件物品中挑选若干件恰好装背包,即使`w1+w2+…+wm=T`,要求找出所有满足上述条件的解。 +例如:当`T=10`,各件物品的体积`{1,8,4,3,5,2}`时,可找到下列`4`组解: +- `(1,4,3,2)` +- `(1,4,5)` +- `(8,2)` +- `(3,5,2)` + +## 实现提示 +可利用回溯法的设计思想来解决背包问题。首先,将物品排成一列,然后,顺序选取物品装入背包,若已选取`i`件物品后未满,则继续选取第`i+1`件,若该件物品“太大”不能装入,则弃之,继续选取下一件,直至背包装满为。 + +如果在剩余的物品中找不到合适的物品以填满背包,则说明“刚刚”装入的物品“不合适”,应将它取出“弃之一”,继续再从“它之后”的物品中选取,如此重复,直到求得满足条件的解,或者无解。 + +由于回溯求解的规则是“后进先出”,自然要用到“栈”。 +进一步考虑:如果每件物品都有体积和价值,背包又有大小限制,求解背包中存放物品总价值最大的问题解---最优解或近似最优解。 diff --git a/1/solution1.c b/1/solution1.c new file mode 100644 index 0000000..bf15a65 --- /dev/null +++ b/1/solution1.c @@ -0,0 +1,48 @@ +#include +#include +#define MAX_N 100 + +int T; +int n; +int w[MAX_N]; +int x[MAX_N]; +int solution_count = 0; + +// 暴力搜索,每个物品都有选和不选两种情况 +void d(int t, int sum, int k) { + if (sum == T) { + solution_count++; + if (solution_count > 50) + return; + int *re = malloc(sizeof(int) * k); + int j = 0; + for (int i = 0; i < k; i++) { + if (x[i]) { + re[j++] = w[i]; + } + } + for (int i = 0; i < j; i++) { + printf("%d ", re[i]); + } + printf("\n"); + } else if (sum < T && k < n) { + x[k] = 1; + d(t + 1, sum + w[k], k + 1); + x[k] = 0; + d(t + 1, sum, k + 1); + } +} + +int main() { + // freopen("data.in", "r", stdin); + // freopen("data.out", "w", stdout); + scanf("%d", &T); + scanf("%d", &n); + for (int i = 0; i < n; i++) { + scanf("%d", &w[i]); + } + d(0, 0, 0); + printf("%d", solution_count); + // printf("Total Solution Count: %d\n", solution_count); + return 0; +} diff --git a/1/solution1.md b/1/solution1.md new file mode 100644 index 0000000..b8e68d3 --- /dev/null +++ b/1/solution1.md @@ -0,0 +1,10 @@ +## 思路 +一个能装入总体积为`T`的背包和`n`件体积分别为`w1,w2,…wn`的物品,能否从`n`件物品中挑选若干件恰好装背包,即使`w1+w2+…+wm=T` + +相当于取一个向量 $n$ = $(x_1, x_2, ..., x_n)$,其中 $x_i \in \{0, 1\}$,使得 $\sum_{i=1}^n x_i w_i = T$,求所有满足条件的 $n$。 + +使用暴力 `dfs` 搜索,搜索每一件物品的选择情况,符合条件时输出。 + +总情况数为 $2^n$,时间复杂度为 $O(2^n)$。 + +## 代码及解释 \ No newline at end of file diff --git a/1/solution2.c b/1/solution2.c new file mode 100644 index 0000000..ed30da9 --- /dev/null +++ b/1/solution2.c @@ -0,0 +1,46 @@ +#include +#include +#define MAX_N 100 + +int T; +int n; +int w[MAX_N]; +int x[MAX_N]; +int solution_count = 0; + +void dfs(int t, int sum, int k) { + if (sum == T) { + solution_count++; + int *re = malloc(sizeof(int) * k); + int j = 0; + for (int i = 0; i < k; i++) { + if (x[i]) { + re[j++] = w[i]; + } + } + for (int i = 0; i < j; i++) { + printf("%d ", re[i]); + } + printf("\n"); + } else if (sum < T && k < n) { + if (sum + w[k] <= T) { + x[k] = 1; + dfs(t + 1, sum + w[k], k + 1); + } + x[k] = 0; + dfs(t + 1, sum, k + 1); + } +} + +int main() { + freopen("data.in", "r", stdin); + freopen("data.out", "w", stdout); + scanf("%d", &T); + scanf("%d", &n); + for (int i = 0; i < n; i++) { + scanf("%d", &w[i]); + } + dfs(0, 0, 0); + printf("Total Solution Count: %d\n", solution_count); + return 0; +} diff --git a/1/solution2.md b/1/solution2.md new file mode 100644 index 0000000..cdd2a21 --- /dev/null +++ b/1/solution2.md @@ -0,0 +1,6 @@ +## 思路 +使用 `dfs`,搜索每一件物品的选择情况,符合条件时输出。 + +使用 `sum+w[k]<=T` 进行剪枝,提高运行速度 + +## 代码及解释 \ No newline at end of file diff --git a/1/solution3.c b/1/solution3.c new file mode 100644 index 0000000..450a309 --- /dev/null +++ b/1/solution3.c @@ -0,0 +1,107 @@ +#include +#include +#define MAX_N 100 + +int T; +int n; +int w[MAX_N]; +int index_arr[MAX_N]; +int solution_count = 0; + +void printSubset(int *subset, int size) { + solution_count++; + for (int i = 0; i < size; i++) { + printf("%d", subset[i]); + if (i != size - 1) { + printf(" "); + } + } + printf("\n"); +} + +void findSubsets(int *arr, int n, int T, int *subset, int size, int index) { + if (T == 0) { + printSubset(subset, size); + return; + } + + if (index == n) { + return; + } + + if (arr[index] > T) { + return; + } + + subset[size] = arr[index]; + findSubsets(arr, n, T - arr[index], subset, size + 1, index + 1); + + while (index < n - 1 && arr[index] == arr[index + 1]) { + index++; + } + findSubsets(arr, n, T, subset, size, index + 1); +} + +void d(int *arr, int n, int T) { + int *subset = (int *)malloc(n * sizeof(int)); + + int size = 0; + findSubsets(arr, n, T, subset, size, 0); + + free(subset); +} + +void swap(int *arr, int i, int j) { + int tmp = arr[i]; + arr[i] = arr[j]; + arr[j] = tmp; + + tmp = index_arr[i]; + index_arr[i] = index_arr[j]; + index_arr[j] = tmp; +} + +void sort(int *arr, int n) { + int i = 0, j = n - 1; + int pivot = arr[0]; + int pivot_index = 0; + while (i < j) { + while (i < j && arr[j] >= pivot) { + j--; + } + if (i < j) { + swap(arr, i, j); + i++; + } + while (i < j && arr[i] <= pivot) { + i++; + } + if (i < j) { + swap(arr, i, j); + j--; + } + } +} + +int main() { + freopen("data.in", "r", stdin); + // freopen("data.out", "w", stdout); + scanf("%d", &T); + scanf("%d", &n); + for (int i = 0; i < n; i++) { + scanf("%d", &w[i]); + index_arr[i] = i; + } + + sort(w, n); + for (int i = 0; i < n; i++) { + printf("%d ", w[i]); + } + printf("\n"); + + + d(w, n, T); + // printf("Total Solution Count: %d\n", solution_count); + printf("%d", solution_count); + return 0; +}