Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- This file is hereby released to the public domain.
- ~aaaaaa123456789, 2015-01-21
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include "common.h"
- int fill_numbers(unsigned short *, unsigned, char **);
- unsigned short validate_row(const unsigned short *, unsigned short);
- unsigned short validate_column(const unsigned short *, unsigned short, unsigned short);
- void assign(const unsigned short *, unsigned short);
- void try_assign(const unsigned short *, unsigned short, unsigned short, unsigned short *, unsigned char *);
- void output(const unsigned short *, unsigned short);
- #define create_map(x) calloc(1, ((x) + 7) >> 3)
- #define set_map(map, x) (((x) >> 3)[(char *) (map)] |= 1 << ((x) & 7))
- #define clear_map(map, x) (((x) >> 3)[(char *) (map)] &= ~(1 << ((x) & 7)))
- #define test_map(map, x) ((((x) >> 3)[(char *) (map)]) & (1 << ((x) & 7)))
- int main (void) {
- // note: this function doesn't release memory before returning -- terminating handles that
- fputs("Enter data (one row per line, numbers separated by spaces, numbers", stderr);
- fputs("range from 1 to n), end with a blank line or EOF:\n", stderr);
- char ** lines = get_lines(0, "", 0, NULL);
- unsigned count = count_lines(lines);
- if (!count) return 0; // nothing to do here
- if (count > 65534) {
- fputs("Too much data.\n", stderr);
- return 1;
- }
- unsigned short * numbers = malloc(count * count * sizeof(unsigned short));
- if (!numbers) {
- fputs("Out of memory.\n", stderr);
- return 1;
- }
- if (!fill_numbers(numbers, count, lines)) return 1;
- free(lines);
- assign(numbers, count);
- return 0;
- }
- int fill_numbers (unsigned short * numbers, unsigned count, char ** lines) {
- char * errp;
- char ** tokens;
- unsigned long rv;
- unsigned linenumber, colnumber;
- for (linenumber = 0; linenumber < count; lines ++, linenumber ++) {
- tokens = tokenize_string(*lines, " ", 1);
- free(*lines);
- if (count_lines(tokens) != count) {
- fprintf(stderr, "ERROR: line %u does not contain %u numbers\n", linenumber + 1, count);
- return 0;
- }
- for (colnumber = 0; colnumber < count; colnumber ++) {
- rv = strtoul(tokens[colnumber], &errp, 10);
- if (*errp) {
- fprintf(stderr, "ERROR: value at (%u, %u) is not a number\n", linenumber + 1, colnumber + 1);
- return 0;
- } else if ((!rv) || (rv > count)) {
- fprintf(stderr, "ERROR: value at (%u, %u) is out of range (expected: 1..%u, got: %lu)\n", linenumber + 1, colnumber + 1, count, rv);
- return 0;
- }
- numbers[linenumber * count + colnumber] = rv;
- }
- free(tokens);
- if (rv = validate_row(numbers + linenumber * count, count)) {
- fprintf(stderr, "ERROR: row %u repeats value %lu\n", linenumber + 1, rv);
- return 0;
- }
- }
- for (colnumber = 0; colnumber < count; colnumber ++)
- if (rv = validate_column(numbers, count, colnumber)) {
- fprintf(stderr, "ERROR: column %u repeats value %lu\n", colnumber + 1, rv);
- return 0;
- }
- return count;
- }
- void assign (const unsigned short * numbers, unsigned short count) {
- unsigned short * assigned = malloc(sizeof(unsigned short) * count);
- memset(assigned, 0, sizeof(unsigned short) * count);
- unsigned char * available = create_map(count);
- try_assign(numbers, count, 0, assigned, available);
- }
- unsigned short validate_row (const unsigned short * row, unsigned short length) {
- char * values = create_map(length);
- while (length --) {
- if (test_map(values, *row - 1)) {
- free(values);
- return *row;
- }
- set_map(values, *row - 1);
- row ++;
- }
- free(values);
- return 0;
- }
- unsigned short validate_column (const unsigned short * numbers, unsigned short count, unsigned short column) {
- if (column >= count) return 0;
- char * values = create_map(count);
- unsigned short p;
- numbers += column;
- for (p = 0; p < count; p ++, numbers += count) {
- if (test_map(values, *numbers - 1)) {
- free(values);
- return *numbers;
- }
- set_map(values, *numbers - 1);
- }
- free(values);
- return 0;
- }
- void try_assign (const unsigned short * numbers, unsigned short count, unsigned short current, unsigned short * assigned, unsigned char * available) {
- if (current >= count) {
- output(assigned, count);
- return;
- }
- unsigned short attempt;
- const unsigned short * p = numbers + count * current;
- for (attempt = 0; attempt < count; attempt ++, p ++) {
- if (assigned[attempt]) continue;
- if (test_map(available, *p - 1)) continue;
- assigned[attempt] = *p;
- set_map(available, *p - 1);
- try_assign(numbers, count, current + 1, assigned, available);
- clear_map(available, *p - 1);
- assigned[attempt] = 0;
- }
- }
- void output (const unsigned short * assigned, unsigned short count) {
- while (-- count) printf("%hu ", *(assigned ++));
- printf("%hu\n", *assigned);
- }
Advertisement
Add Comment
Please, Sign In to add comment