更新第一题

This commit is contained in:
Luthics 2023-11-28 19:11:55 +08:00
parent ad465c2b7d
commit 8f85e5eec8
10 changed files with 282 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
*.exe
.vscode/*
template/*
*.zip
*/datas/*

3
1/data.in Normal file
View File

@ -0,0 +1,3 @@
10
6
1 8 4 3 5 2

5
1/data.out Normal file
View File

@ -0,0 +1,5 @@
1 4 3 2
1 4 5
8 2
3 5 2
4

37
1/make_data.py Normal file
View File

@ -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")

15
1/problem.md Normal file
View File

@ -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`件,若该件物品“太大”不能装入,则弃之,继续选取下一件,直至背包装满为。
如果在剩余的物品中找不到合适的物品以填满背包,则说明“刚刚”装入的物品“不合适”,应将它取出“弃之一”,继续再从“它之后”的物品中选取,如此重复,直到求得满足条件的解,或者无解。
由于回溯求解的规则是“后进先出”,自然要用到“栈”。
进一步考虑:如果每件物品都有体积和价值,背包又有大小限制,求解背包中存放物品总价值最大的问题解---最优解或近似最优解。

48
1/solution1.c Normal file
View File

@ -0,0 +1,48 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}

10
1/solution1.md Normal file
View File

@ -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)$。
## 代码及解释

46
1/solution2.c Normal file
View File

@ -0,0 +1,46 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}

6
1/solution2.md Normal file
View File

@ -0,0 +1,6 @@
## 思路
使用 `dfs`,搜索每一件物品的选择情况,符合条件时输出。
使用 `sum+w[k]<=T` 进行剪枝,提高运行速度
## 代码及解释

107
1/solution3.c Normal file
View File

@ -0,0 +1,107 @@
#include <stdio.h>
#include <stdlib.h>
#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;
}