/*
** necklace.c
** 2009-06-19: Correction about the inline result for case "3".
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
typedef unsigned int uint;
void usage(FILE * f, char * binname)
{
fprintf(f, "Usage: %s size\n", binname);
}
void set_ball(int * balls, int size, int index, int ball)
{
balls[index - size] = ball;
balls[index] = ball;
balls[index + size] = ball;
}
int get_bit(uint * bits, uint n)
{
return (bits[(n >> 5)] >> (n & 0x001f)) & 1;
}
int set_bit(uint * bits, uint n)
{
uint shift, bit;
bits += (n >> 5);
bit = (1ul << (n & 0x001f));
if(*bits & bit) {
return 1;
} else {
*bits |= bit;
return 0;
}
}
void clear_bit(uint * bits, uint n)
{
bits[n >> 5] ^= (1ul << (n & 0x001f));
}
int count_successive_bits(uint * bits)
{
int c = 0;
uint last;
while(*bits == 0xfffffffful) {
c += 32;
bits++;
}
last = *bits;
while(last & 1) {
c++;
last >>= 1;
}
return c;
}
int countup(int * balls, uint * bits, int size, int index)
{
int width, from, to, sum, i;
set_bit(bits, balls[index]);
for(width = 2; width < size; width++) {
to = index + width;
sum = 0;
for(i = index; i < to; i++) {
if(balls[i]) {
sum += balls[i];
} else {
to = i;
}
}
from = to - width;
i = index;
while(from < i--) {
if(balls[i]) {
sum += balls[i];
} else {
from = i + 1;
}
}
if(to < from + width) {
return 1;
}
if(set_bit(bits, sum)) {
return 0;
}
while(index < --to) {
if(balls[--from] && balls[to]) {
sum += balls[from] - balls[to];
if(set_bit(bits, sum)) {
return 0;
}
} else {
break;
}
}
}
if(index == to && balls[index + 1]) {
sum += balls[index + 1];
if(set_bit(bits, sum)) {
return 0;
}
}
return 1;
}
int permute(int * last, int size, int len, int remain)
{
int i;
int ball;
ball = count_successive_bits((uint *) (last + size * 3));
if(remain == 0) {
if(ball <= size * (size - 1) + 1) {
return 0;
}
fprintf(stdout, "%d", last[0]);
if(last[1] < last[size - 1]) {
for(i = 1; i < size; i++) {
fprintf(stdout, " %d", last[i]);
}
} else {
for(i = size - 1; 0 < i; i--) {
fprintf(stdout, " %d", last[i]);
}
}
fprintf(stdout, "\n");
fflush(stdout);
return 1;
} else if(remain < ball) {
return 0;
} else {
int * current, * balls;
uint * bits;
int result = 0;
remain -= ball;
current = last + len;
balls = current + size;
bits = (uint *) (balls + size * 2);
for(i = 1; i < size; i++) {
if(last[i] == 0) {
memcpy(current, last, len);
set_ball(balls, size, i, ball);
if(countup(balls, bits, size, i)) {
result += permute(current, size, len, remain);
}
}
}
return result;
}
}
int main(int argc, char ** argv)
{
int size, len, half, sum, result, i;
int * buffer, * balls;
uint * bits;
char dummy[2];
if(argc == 1) {
usage(stdout, argv[0]);
exit(0);
}
if(2 < argc || sscanf(argv[1], "%ld%1s", &size, dummy) != 1 || size < 1) {
fprintf(stderr, "Error: Invalid Argument.\nArgument shall be a positive integer as size of neckless.\n");
usage(stderr, argv[0]);
exit(1);
}
switch(size) {
case 1:
fprintf(stdout, "For 1 ball:\n1\n");
result = 1;
break;
case 2:
fprintf(stdout, "For 2 balls:\n1 2\n");
result = 1;
break;
case 3:
fprintf(stdout, "For 3 balls:\n1 2 4\n");
result = 1;
break;
case 4:
fprintf(stdout, "For 4 balls:\n1 2 6 4\n1 3 2 7\n");
result = 2;
break;
default:
fprintf(stdout, "For %d balls:\n", size);
half = (size + 1) / 2;
sum = (size * (size - 1)) + 1;
len = sizeof(int) * ((sum + 1) / 32 + 1 + size * 3);
buffer = (int *) malloc(len * (size - 1));
if(buffer == 0) {
fprintf(stderr, "Error: Memory allocation Failure.\nTry with lesser size, or kill other processes and assign more swaps.\n");
usage(stderr, argv[0]);
exit(1);
}
memset(buffer, 0, len * (size - 1));
balls = buffer + size;
bits = (uint *) (buffer + size * 3);
set_ball(balls, size, 0, 1);
set_ball(balls, size, 1, 2);
*bits = 0x000ful;
result = permute(buffer, size, len, sum - 3);
set_ball(balls, size, 1, 0);
*bits = 0x0007ul;
for(i = 2; i < half; i++) {
set_ball(balls, size, i, 2);
result += permute(buffer, size, len, sum - 3);
set_ball(balls, size, i, 0);
}
if((size & 1) == 0) {
int last;
last = half - 1;
set_ball(balls, size, half, 2);
set_ball(balls, size, 1, 3);
*bits = 0x001ful;
result += permute(buffer, size, len, sum - 6);
set_ball(balls, size, 1, 0);
*bits = 0x000ful;
for(i = 2; i < last; i++) {
set_ball(balls, size, i, 3);
result += permute(buffer, size, len, sum - 6);
set_ball(balls, size, i, 0);
}
set_ball(balls, size, last, 3);
*bits = 0x002ful;
result += permute(buffer, size, len, sum - 6);
}
}
if(result == 0) {
fprintf(stdout, "No pattern was found.\n");
} else if(result == 1) {
fprintf(stdout, "Totally, 1 pattern was found.\n");
} else {
fprintf(stdout, "Totally, %d patterns were found.\n", result);
}
exit(0);
}