pz12_gavrilov

This is a task for our favourite professor
git clone git://git.stellar-nexus.ru/pz12_gavrilov
Log | Files | Refs

commit 053934bc19eebd3b7cb44312d451cfe8789d4dd4
Author: Plat <plat@stellar-nexus.ru>
Date:   Tue, 25 Nov 2025 00:23:51 +0000

Initial commit

Diffstat:
AMakefile | 26++++++++++++++++++++++++++
Aknapsack.c | 167+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aknapsack.h | 3+++
Aknapsack_single.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asort.c | 57+++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asort.h | 4++++
Asort_single.c | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
7 files changed, 364 insertions(+), 0 deletions(-)

diff --git a/Makefile b/Makefile @@ -0,0 +1,26 @@ +BIN1 =\ + bell \ + greed \ + full + +BIN2 =\ + bubble \ + choice \ + insert \ + shell + +include config.mk + + +all: ${BIN1} ${BIN2} + +${BIN1}: + ${CC} ${CFLAGS} ${LDFLAGS} -D"$@" knapsack_single.c knapsack.c -o "$@" + strip "$@" + +${BIN2}: + ${CC} ${CFLAGS} ${LDFLAGS} -D"$@" sort_single.c sort.c -o "$@" + strip "$@" + +clean: + rm -f ${BIN1} ${BIN2} diff --git a/knapsack.c b/knapsack.c @@ -0,0 +1,167 @@ +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#include "util.h" + +int +knapsack_bell(unsigned int k, unsigned int w, int m[k], int c[k], int out[k]) +{ + int (*opt)[w+1] = malloc(sizeof(*opt * (k+1))); + if (!opt) { + errno = ENOMEM; + return -1; + } + + for (unsigned int i = 0; i <= k; ++i) { + for (int wi = 0; wi <= w; ++wi) { + if (i == 0 || wi == 0) + opt[i][wi] = 0; + else if (m[i-1] > wi) + opt[i][wi] = opt[i-1][wi]; + else + opt[i][wi] = MAX + ( + opt[i-1][wi], + c[i-1] + opt[i-1][wi - m[i-1]] + ); + } + } + + unsigned int idx = 0; + for (; k > 0; --k) { + if (opt[k][w] != opt[k-1][w]) { + out[idx++] = k - 1; + w -= m[k-1]; + } + } + + out[idx] = -1; + for (unsigned int ogidx = --idx, temp; idx > ogidx/2; --idx) { + temp = out[idx]; + out[idx] = out[ogidx-idx]; + out[ogidx-idx] = temp; + } + + free(opt); +} + +static void +sift_down(unsigned int n, float a[n], unsigned int idx[n], unsigned int root) +{ + while (1) { + int left = 2 * root + 1; + int right = left + 1; + int largest = root; + + if (left < n && a[left] > a[largest]) + largest = left; + if (right < n && a[right] > a[largest]) + largest = right; + + if (largest == root) + break; + + float tmp = a[root]; + a[root] = a[largest]; + a[largest] = tmp; + + unsigned int tmpi = idx[root]; + idx[root] = idx[largest]; + idx[largest] = tmpi; + + root = largest; + } +} + +static void +heap_build(unsigned int n, float a[n], unsigned int idx[n]) +{ + for (int i = n / 2 - 1; i >= 0; --i) + sift_down(n, a, idx, i); +} + +static unsigned int +extract_max(unsigned int *n, float a[*n], unsigned int idx[*n]) +{ + if (*n == 0) + return UINT_MAX; + + unsigned int max_index = idx[0]; + + --*n; + a[0] = a[*n]; + idx[0] = idx[*n]; + + sift_down(*n, a, idx, 0); + + return max_index; +} + +int +knapsack_greed(unsigned int k, unsigned int w, int m[k], int c[k], int out[k]) +{ + unsigned int *indices = malloc(sizeof(*indices) * k); + float *density = malloc(sizeof(*density) * k); + if (!indices || !density) { + errno = ENOMEM; + return -1; + } + for (unsigned int i = 0; i < k; ++i) { + indices[i] = i; + density[i] = (float)c[i]/m[i]; + } + unsigned int heap_size = k; + heap_build(heap_size, density, indices); + + unsigned int out_len = 0; + unsigned long weight = 0; /* weight can be larger than w - use long */ + while (heap_size > 0) { + unsigned int pos = extract_max(&heap_size, density, indices); + if (pos == UINT_MAX) + break; + + weight += m[pos]; + if (weight > w) + weight -= m[pos]; + else if (weight < w) + out[out_len++] = pos; + else + break; + } + + out[out_len] = -1; + free(indices); + free(density); +} + +int +knapsack_full(unsigned int k, unsigned int w, int m[k], int c[k], int out[k]) +{ + if (k > sizeof(long)*8) { + errno = ERANGE; + return -1; + } + unsigned long best_cost = 0; + for (unsigned long list = 0; list < (1UL << k); ++list) { + unsigned long weight = 0, cost = 0; + for (unsigned int i = 0; i < k; ++i) { + if (!(list & (1UL << i))) + continue; + weight += m[i]; + if (weight > w) + break; + cost += c[i]; + } + + if (cost > best_cost) { + best_cost = cost; + unsigned int out_len = 0; + for (unsigned int i = 0; i < k; ++i) { + if (list & (1UL << i)) + out[out_len++] = i; + } + out[out_len] = -1; + } + } +} diff --git a/knapsack.h b/knapsack.h @@ -0,0 +1,3 @@ +int knapsack_bell(unsigned int k, unsigned int w, int m[k], int c[k], int out[k]); +int knapsack_greed(unsigned int k, unsigned int w, int m[k], int c[k], int out[k]); +int knapsack_full(unsigned int k, unsigned int w, int m[k], int c[k], int out[k]); diff --git a/knapsack_single.c b/knapsack_single.c @@ -0,0 +1,56 @@ +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <time.h> + +#include "knapsack.h" +#include "util.h" + +#ifdef bell +#define knapsack knapsack_bell +#elif defined(greed) +#define knapsack knapsack_greed +#elif defined(full) +#define knapsack knapsack_full +#else +#error You need to define either bell, greed, or full +#endif + +static long long int +input(long long mivnal, long long maxval) +{ + unsigned char len = 0, arr[UCHAR_MAX]; + + for (int c = getchar(); !isspace(c) && c != EOF; c = getchar()) + arr[len++] = c; + arr[len] = '\0'; + return estrtonum(arr, minval, maxval); + +} + +int +main(void) +{ + unsigned int k = input(0, UINT_MAX), + w = input(0, UINT_MAX); + int *m = emalloc(sizeof(*m) * k), + *c = emalloc(sizeof(*c) * k); + + unsigned int len; + for (len = 0; len < k; ++len) + m[len] = input(0, INT_MAX); + for (len = 0; len < k; ++len) + c[len] = input(0, INT_MAX); + if (getchar() != EOF) + weprintf("More than %d numbers provided - ignoring them\n", k); + + int *out = emalloc(sizeof(*out) * k); + clock_t solve_time = clock(); + if (knapsack(k, w, m, c, out) < 0) + eprintf("knapsack:"); + solve_time = clock() - solve_time; + printf("%f\n", solve_time / CLOCKS_PER_SEC); + for (len = 0; len + 1 < k && out[len+1] > 0; ++len) + printf("%d ", out[len]); + printf("%d\n", out[len]); +} diff --git a/sort.c b/sort.c @@ -0,0 +1,57 @@ +void +bubble_sort(unsigned int n, int a[n]) +{ + int tmp; + for (unsigned int i = 0; i < n - 1; ++i) { + for (unsigned int j = 0; j < n - i - 1; ++j) { + if (a[j] > a[j+1]) { + tmp = a[j]; + a[j] = a[j+1]; + a[j+1] = tmp; + } + } + } + +} + +void +choice_sort(unsigned int n, int a[n]) /* it's actually insertion_sort :nerd: */ +{ + int tmp; + for (unsigned int i = 0; i < n - 1; ++i) { + int min = i; + for (unsigned int j = i + 1; j < n; ++j) { + if (a[j] < a[min]) + min = j; + } + tmp = a[i]; + a[i] = a[min]; + a[min] = tmp; + } +} + +void +insert_sort(unsigned int n, int a[n]) +{ + int key; + for (unsigned int i = 1; i < n; ++i) { + key = a[i]; + for (unsigned int j = i - 1; j >= 0 && a[j] > key; --j) + a[j+1] = a[j]; + a[j+1] = key; + } +} + +void +shell_sort(unsigned int n, int a[n]) +{ + int tmp; + for (unsigned int gap = n/2; gap > 0; gap /= 2) { + for (unsigned int i = gap; i < n; ++i) { + tmp = a[i]; + for (unsigned int j = i; j >= gap && a[j-gap] > tmp; j -= gap) + a[j] = a[j-gap]; + a[j] = tmp; + } + } +} diff --git a/sort.h b/sort.h @@ -0,0 +1,4 @@ +void bubble_sort(unsigned int n, int a[n]); +void choice_sort(unsigned int n, int a[n]); +void insert_sort(unsigned int n, int a[n]); +void shell_sort(unsigned int n, int a[n]); diff --git a/sort_single.c b/sort_single.c @@ -0,0 +1,51 @@ +#include <ctype.h> +#include <limits.h> +#include <stdio.h> +#include <time.h> + +#include "sort.h" +#include "util.h" + +#ifdef bubble +#define sort bubble_sort +#elif defined(choice) +#define sort choice_sort +#elif defined(insert) +#define sort insert_sort +#elif defined(shell) +#define sort shell_sort +#else +#error You need to define either bubble, choice, insert, or shell +#endif + +static long long int +input(long long mivnal, long long maxval) +{ + unsigned char len = 0, arr[UCHAR_MAX]; + + for (int c = getchar(); !isspace(c) && c != EOF; c = getchar()) + arr[len++] = c; + arr[len] = '\0'; + return estrtonum(arr, minval, maxval); + +} + +int +main(void) +{ + unsigned int n = input(0, UINT_MAX), + int *arr = emalloc(sizeof(*arr) * n); + + unsigned int len; + for (len = 0; len < n; ++len) + arr[len] = input(0, INT_MAX); + if (getchar() != EOF) + weprintf("More than %d numbers provided - ignoring them\n", n); + + clock_t solve_time = clock(); + sort(n, arr); + solve_time = clock() - solve_time; + printf("%f\n", solve_time / CLOCKS_PER_SEC); + for (len = 0; len < k; ++len) + printf("%d\n", out[len]); +}