puzzles/coin-combo/coincombo.c

90 lines
2.4 KiB
C
Raw Normal View History

2024-04-02 21:01:09 +00:00
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEBUG 0
#define IMPOSSIBLE (INT_MAX >> 1)
int main(int argc, char **argv) {
int num_coins, amount;
int *coins;
int *m;
if (argc < 2) {
fprintf(stderr, "Usage: %s NUM_COINS [COINS ...]\n", argv[0]);
return 1;
}
amount = atoi(argv[1]);
num_coins = argc - 2;
coins = malloc(num_coins * sizeof(int));
for (int i = 0; i < num_coins; i++) {
coins[i] = atoi(argv[i + 2]);
}
m = calloc((num_coins + 1) * (amount + 1), sizeof(int));
for (int j = 1; j < amount + 1; j++) {
m[j * (num_coins + 1)] = IMPOSSIBLE;
}
for (int i = 1; i < num_coins + 1; i++) {
int coin = coins[i - 1];
for (int r = 1; r < amount + 1; r++) {
if (coin == r) {
m[r * (num_coins + 1) + i] = 1;
} else if (coin > r) {
m[r * (num_coins + 1) + i] = m[r * (num_coins + 1) + i - 1];
} else {
int solution_a = m[r * (num_coins + 1) + i - 1];
int solution_b = 1 + m[(r - coin) * (num_coins + 1) + i];
if (solution_a < solution_b) {
m[r * (num_coins + 1) + i] = solution_a;
} else {
m[r * (num_coins + 1) + i] = solution_b;
}
}
}
}
if (DEBUG) {
for (int i = 1; i < num_coins + 1; i++) {
for (int j = 0; j < amount + 1; j++) {
if (m[j * (num_coins + 1) + i] == IMPOSSIBLE) {
printf("---- ");
} else {
printf("%4d ", m[j * (num_coins + 1) + i]);
}
}
printf("\n");
}
}
int i = num_coins;
int j = amount;
char output[256] = "";
char *cur = output, *const end = output + sizeof(output);
while (j != 0) {
int coin = coins[i - 1];
if (j >= coin && m[(j - coin) * (num_coins + 1) + i] == m[j * (num_coins + 1) + i] - 1) {
if (j == coin) {
printf("%s%d\n", output, coin);
} else {
cur += snprintf(cur, end - cur, "%d, ", coin);
}
j -= coin;
} else if (i > 0) {
i--;
} else {
break;
}
}
free(m);
free(coins);
return 0;
}