C, 16.344 (4 minutes 33 seconds)
Best moves found so far: D6,D13,R19,D9,D11,R21,D10,R20
Uses a mixture of Monte Carlo and hill climbing. Could be made to run much faster, I'm sure.
#include <stdio.h>
#include <stdlib.h>
/*
Best result so far: 16.344
D6,D13,R19,D9,D11,R21,D10,R20
real 4m33.027s
user 4m12.787s
sys 0m1.334s
*/
#define GRID_WIDTH 40
#define GRID_HEIGHT 20
#define GRID_SIZE (GRID_WIDTH * GRID_HEIGHT)
#define NUM_FOLDS 8
#define MAX_VALUE (1 << NUM_FOLDS)
#define TARGET_VALUE (MAX_VALUE / 2)
double score_grid(short *g) {
int i, sum;
for (i=sum=0; i<GRID_SIZE; i++) sum += abs(*g++ - TARGET_VALUE);
return sum * 1.0 / MAX_VALUE;
}
void h_fold(short *g, int fold_row) {
int x, y0, y1;
if (fold_row<1 || fold_row>=GRID_HEIGHT) return;
y1 = fold_row * GRID_WIDTH;
y0 = y1 - GRID_WIDTH;
while (y0>=0 && y1<GRID_SIZE) {
for (x=0; x<GRID_WIDTH; x++) {
g[y0+x] = g[y1+x] = (g[y0+x] + g[y1+x]) >> 1;
}
y0 -= GRID_WIDTH;
y1 += GRID_WIDTH;
}
}
void v_fold(short *g, int fold_col) {
int y, x0, x1;
if (fold_col<1 || fold_col>=GRID_WIDTH) return;
x1 = fold_col;
x0 = x1 - 1;
while (x0>=0 && x1<GRID_WIDTH) {
for (y=0; y<GRID_SIZE; y+=GRID_WIDTH) {
g[y+x0] = g[y+x1] = (g[y+x0] + g[y+x1]) >> 1;
}
x0--;
x1++;
}
}
void print_grid(short *g) {
int i=0, checksum=0;
while (i<GRID_SIZE) {
checksum += *g;
printf("%3X",*g++);
if ((++i) % GRID_WIDTH == 0) putchar('\n');
}
if (checksum != GRID_SIZE * TARGET_VALUE) printf("Bad total: %d\n",checksum);
}
void init_grid(short *g) {
int i;
static short *start_grid=0, *sg;
if (!start_grid) {
char *src = "11010110100011100000001000110001001101010111000100100100000101100000101111000010"
"10110011111011111101101011111001000010101010110111000101000001011111101000011001"
"10000111111001111011100101101001101100001110001101001011010011011110101000011100"
"00110010100010100010110101001100110001100100111010000110100110001000110000111101"
"01000001110000101000110101011011101010111110101010110000001011010010000011101000"
"11111011111100100100100010111010111111000101011110000100111111111000110101101101"
"00110100010111101111000011011010000110001001101010010101110010110111101001011111"
"10110001101100001110010100110100010011011110100110000100100111101101000010011001"
"00011100110100111101000000001000010100001101001011000101101001000100111100011010"
"00010110001110011111100011101111011100111001110011111011010010000100101111101001";
start_grid = malloc(GRID_SIZE * sizeof(short));
for (i=0; i<GRID_SIZE; i++) start_grid[i] = (src[i]&1)<<NUM_FOLDS;
}
sg = start_grid;
for (i=0; i<GRID_SIZE; i++) *g++ = *sg++;
}
double evaluate(int *moves) {
short *grid;
double score;
int i, f;
grid = malloc(GRID_SIZE * sizeof(short));
init_grid(grid);
for (i=0; i<NUM_FOLDS; i++) {
f = moves[i];
if (f>0) v_fold(grid,f);
else h_fold(grid,-f);
}
score = score_grid(grid);
free(grid);
return score;
}
double optimize_folding(int *moves, double score) {
int opt_cycle, i, which_fold, new_move, f1, f2, t;
double s;
for (opt_cycle=0; opt_cycle<1000; opt_cycle++) {
for (i=0; i<NUM_FOLDS; i++) {
which_fold = random() % NUM_FOLDS;
do {
if (random()&1) new_move = random() % (GRID_WIDTH-1) + 1;
else new_move = -(random() % (GRID_HEIGHT-1) + 1);
} while (moves[which_fold]==new_move);
t = moves[which_fold];
moves[which_fold] = new_move;
s = evaluate(moves);
if (s>score) moves[which_fold] = t;
else score = s;
}
for (i=0; i<NUM_FOLDS; i++) {
f1 = random() % NUM_FOLDS;
do {
f2 = random() % NUM_FOLDS;
} while (f2==f1);
t = moves[f1];
moves[f1] = moves[f2];
moves[f2] = t;
s = evaluate(moves);
if (s>score) {
t = moves[f1];
moves[f1] = moves[f2];
moves[f2] = t;
}
else score = s;
}
}
return score;
}
void show_moves(int *moves) {
int i, m;
for (i=0; i<NUM_FOLDS; i++) {
m = moves[i];
printf("%c%d%c",(m>0)?'R':'D',abs(m),((i+1)%NUM_FOLDS)?',':'\n');
}
}
int main() {
int i, j, moves[NUM_FOLDS], save_moves[NUM_FOLDS];
double score, best_score = 1.0E+99;
srandomdev();
for (i=0; i<400; i++) {
for (j=0; j<NUM_FOLDS; j++) {
if (random()&1) moves[j] = random() % (GRID_WIDTH-1) + 1;
else moves[j] = -(random() % (GRID_HEIGHT-1) + 1);
}
score = optimize_folding(moves, 1.0E+99);
if (score<best_score) {
best_score = score;
for (j=0; j<NUM_FOLDS; j++) save_moves[j]=moves[j];
}
}
printf("%.3lf\n",best_score);
show_moves(save_moves);
return 0;
}