#include #include #include long starttime = clock(); typedef struct block { char type; char n; char x[4]; char y[4]; char z[4]; }; typedef struct bigblock { char n; char x[60]; char y[60]; char z[60]; }; int blocks = 0; bigblock goal; block list[200]; int blockcompare (const void *a, const void *b) { block *v1 = (block *)a; block *v2 = (block *)b; if (v1->type < 5) { if (v2->type < 5) return v1->type - v2->type; else return -1; } if (v2->type < 5) return 1; return v2->type - v1->type; } void blocknormalize (block &a) { int minx = 10, miny = 10, minz = 10; int i; for (i = 0; i < a.n; i++) { if (a.x[i] < minx) minx = a.x[i]; if (a.y[i] < miny) miny = a.y[i]; if (a.z[i] < minz) minz = a.z[i]; } for (i = 0; i < a.n; i++) { a.x[i] = a.x[i] - minx + 1; a.y[i] = a.y[i] - miny + 1; a.z[i] = a.z[i] - minz + 1; } for (i = 0; i < a.n; i++) for (int j = i+1; j < a.n; j++) if (a.x[i] + 10*a.y[i] + 100*a.z[i] < a.x[j] + 10*a.y[j] + 100*a.z[j]) { int tx, ty, tz; tx = a.x[i]; ty = a.y[i]; tz = a.z[i]; a.x[i] = a.x[j]; a.y[i] = a.y[j]; a.z[i] = a.z[j]; a.x[j] = tx; a.y[j] = ty; a.z[j] = tz; } } void readblock (ifstream &input, block &a) { int temp; input >> temp; a.type = temp; input >> temp; a.n = temp; for (int i = 0; i < a.n; i++) { input >> temp; a.x[i] = temp; input >> temp; a.y[i] = temp; input >> temp; a.z[i] = temp; } blocknormalize(a); } void readblock (ifstream &input, bigblock &a) { int temp; input >> temp; a.n = temp; for (int i = 0; i < a.n; i++) { input >> temp; a.x[i] = temp; input >> temp; a.y[i] = temp; input >> temp; a.z[i] = temp; } } void blockassign (block &a, block &b) { a.type = b.type; a.n = b.n; for (int i = 0; i < a.n; i++) { a.x[i] = b.x[i]; a.y[i] = b.y[i]; a.z[i] = b.z[i]; } } int blockacontainsb (block &a, block &b) { for (int i = 0; i < a.n; i++) { int ok = 0; for (int j = 0; j < b.n; j++) if (a.x[i] == b.x[j] && a.y[i] == b.y[j] && a.z[i] == b.z[j]) ok = 1; if (!ok) return 0; } return 1; } int blockacontainsb (bigblock &a, block &b, int tx, int ty, int tz) { for (int i = 0; i < a.n; i++) { int ok = 0; for (int j = 0; j < b.n; j++) if (a.x[i] == b.x[j]+tx && a.y[i] == b.y[j]+ty && a.z[i] == b.z[j]+tz) ok = 1; if (!ok) return 0; } return 1; } int blockequal (block &a, block &b) { if (a.n != b.n) return 0; return blockacontainsb (a,b); } void blockrotate (block &a, int axis, int n) { if (n == 0) return; for (int i = 0; i < a.n; i++) { int ox = a.x[i]; int oy = a.y[i]; int oz = a.z[i]; if (axis == 0) { a.y[i] = ox; a.x[i] = -oy; } if (axis == 1) { a.z[i] = ox; a.x[i] = -oz; } if (axis == 2) { a.z[i] = oy; a.y[i] = -oz; } } blockrotate (a, axis, n-1); } int done[60]; int loners = 0; int left; int best = 1000; int bestpieces[100]; int placed; int placedpieces[100]; int pieceat[10][10][10]; int buddies[60]; int buddiesleft[60]; int buddylist[60][4]; int placepiece(int p, int spot) { int dx = goal.x[spot] - list[p].x[0]; int dy = goal.y[spot] - list[p].y[0]; int dz = goal.z[spot] - list[p].z[0]; int j; int severs = 0; placedpieces[placed++] = list[p].type; left -= list[p].n; for (j = 0; j < list[p].n; j++) { int k = pieceat [dx + list[p].x[j]] [dy + list[p].y[j]] [dz + list[p].z[j]]; done[k] = 1; for (int n = 0; n < buddies[k]; n++) { buddiesleft[buddylist[k][n]]--; if (buddiesleft[buddylist[k][n]] == 0) loners++; } } for (j = 0; j < list[p].n; j++) { int k = pieceat [dx + list[p].x[j]] [dy + list[p].y[j]] [dz + list[p].z[j]]; for (int n = 0; n < buddies[k]; n++) if (!done[buddylist[k][n]]) severs++; } if (p == 0 && buddies[spot] == 0) loners--; return severs; } void unplacepiece(int p, int spot) { int dx = goal.x[spot] - list[p].x[0]; int dy = goal.y[spot] - list[p].y[0]; int dz = goal.z[spot] - list[p].z[0]; placed--; left += list[p].n; for (int j = 0; j < list[p].n; j++) { int k = pieceat [dx + list[p].x[j]] [dy + list[p].y[j]] [dz + list[p].z[j]]; done[k] = 0; for (int n = 0; n < buddies[k]; n++) { buddiesleft[buddylist[k][n]]++; if (buddiesleft[buddylist[k][n]] == 1) loners--; } } if (p == 0 && buddies[spot] == 0) loners++; } void fillblock(int start) { if (clock() - starttime >= 5*CLK_TCK) return; if (left == 0) { if (placed < best) { best = placed; for (int i = 0; i < placed; i++) bestpieces[i] = placedpieces[i]; } return; } if (start < 0) return; if (start == 0) { for (int spot = 0; done[spot] == 1; spot++); placepiece(0, spot); fillblock(start); unplacepiece(0, spot); return; } for (int bi = start; bi >= 0; bi--) { if (list[bi].n * (best-placed-1) < left) return; for (int i = 0; i < goal.n; i++) if (!done[i]) { int works = 1, j; int dx = goal.x[i] - list[bi].x[0]; int dy = goal.y[i] - list[bi].y[0]; int dz = goal.z[i] - list[bi].z[0]; for (j = 0; j < list[bi].n; j++) { int k = pieceat [dx + list[bi].x[j]] [dy + list[bi].y[j]] [dz + list[bi].z[j]]; if (k == -1 || done[k]) { works = 0; break; } } if (!works) continue; placepiece(bi, i); fillblock(bi); unplacepiece(bi, i); } } } void guessblock (int start) { if (left == 0) { if (placed < best) { best = placed; for (int i = 0; i < placed; i++) bestpieces[i] = placedpieces[i]; } return; } if (start < 0) return; if (start == 0) { for (int spot = 0; done[spot] == 1; spot++); placepiece(0, spot); guessblock(start); unplacepiece(0, spot); return; } int maxhit = 10; int minsevers = 10000; int minseverbi; int minseveri; for (int bi = start; bi >= 0; bi--) { for (int i = 0; i < goal.n; i++) if (!done[i]) { int works = 1, j; int dx = goal.x[i] - list[bi].x[0]; int dy = goal.y[i] - list[bi].y[0]; int dz = goal.z[i] - list[bi].z[0]; for (j = 0; j < list[bi].n; j++) { int k = pieceat [dx + list[bi].x[j]] [dy + list[bi].y[j]] [dz + list[bi].z[j]]; if (k == -1 || done[k]) { works = 0; break; } } if (!works) continue; int cursevers = placepiece(bi, i); unplacepiece(bi, i); if (list[bi].n > maxhit || list[bi].n == maxhit && cursevers < minsevers) { maxhit = list[bi].n; minsevers = cursevers; minseveri = i; minseverbi = bi; } } } placepiece(minseverbi, minseveri); guessblock(blocks-1); unplacepiece(minseverbi, minseveri); } void blockoutput (block &a, ofstream &output) { output << "Type: " << int(a.type) << "\n"; output << "Coordinates:\n"; for (int i = 0; i < a.n; i++) output << int(a.x[i]) << " " << int(a.y[i]) << " " << int(a.z[i]) << "\n"; output << "\n"; } int main() { ifstream input; ofstream output; int i; input.open ("block.in"); output.open ("block.out"); readblock(input, goal); input.close (); input.open ("types.in"); // Build the block list for (int type = 0; type < 12; type++) { int start = blocks; block model; readblock(input, model); for (int xr = 0; xr < 4; xr++) for (int yr = 0; yr < 4; yr++) for (int zr = 0; zr < 4; zr++) { block temp; blockassign (temp, model); blockrotate (temp, 0, xr); blockrotate (temp, 1, yr); blockrotate (temp, 2, zr); blocknormalize (temp); int match = 0; for (int u = start; u < blocks && !match; u++) if (blockequal (list[u], temp)) match = 1; if (match) continue; blockassign (list[blocks++], temp); } } for (i = 0; i < goal.n; i++) buddies[i] = 0; for (i = 0; i < goal.n; i++) for (int j = 0; j < goal.n; j++) if ( (goal.x[i] - goal.x[j]) * (goal.x[i] - goal.x[j]) + (goal.y[i] - goal.y[j]) * (goal.y[i] - goal.y[j]) + (goal.z[i] - goal.z[j]) * (goal.z[i] - goal.z[j]) == 1) { buddylist[i][buddies[i]] = j; buddiesleft[i]++; buddies[i]++; } for (i = 0; i < goal.n; i++) if (buddies[i] == 0) loners++; left = goal.n; for (i = 0; i < 60; i++) done[i] = 0; for (int x = 0; x < 10; x++) for (int y = 0; y < 10; y++) for (int z = 0; z < 10; z++) pieceat[x][y][z] = -1; for (i = 0; i < goal.n; i++) pieceat[goal.x[i]][goal.y[i]][goal.z[i]] = i; qsort (list, blocks, sizeof(list[0]), blockcompare); fillblock(blocks-1); output << best << "\n"; for (i = 0; i < best; i++) { output << bestpieces[i]; if (i == best - 1) output << "\n"; else output << " "; } cout << loners << "\n"; /* for (int t = 0; t < blocks; t++) { output << "Index: " << t << "\n"; blockoutput(list[t], output); }*/ input.close (); output.close (); return 0; }