USACO section 3.2 Magic Squares(STL+广搜)
IOI'96
Following the success of the magic cube, Mr. Rubik invented its planar version, called magic squares. This is a sheet composed of 8 equal-sized squares:
1 | 2 | 3 | 4 |
8 | 7 | 6 | 5 |
In this task we consider the version where each square has a different color. Colors are denoted by the first 8 positive integers. A sheet configuration is given by the sequence of colors obtained by reading the colors of the squares starting at the upper left corner and going in clockwise direction. For instance, the configuration of Figure 3 is given by the sequence (1,2,3,4,5,6,7,8). This configuration is the initial configuration.
Three basic transformations, identified by the letters `A', `B' and `C', can be applied to a sheet:
- 'A': exchange the top and bottom row,
- 'B': single right circular shifting of the rectangle,
- 'C': single clockwise rotation of the middle four squares.
Below is a demonstration of applying the transformations to the initial squares given above:
A: |
|
B: |
|
C: |
|
All possible configurations are available using the three basic transformations.
You are to write a program that computes a minimal sequence of basic transformations that transforms the initial configuration above to a specific target configuration.
PROGRAM NAME: msquare
INPUT FORMAT
A single line with eight space-separated integers (a permutation of (1..8)) that are the target configuration.
SAMPLE INPUT (file msquare.in)
2 6 8 4 5 7 3 1
OUTPUT FORMAT
Line 1: | A single integer that is the length of the shortest transformation sequence. |
Line 2: | The lexically earliest string of transformations expressed as a string of characters, 60 per line except possibly the last line. |
SAMPLE OUTPUT (file msquare.out)
7 BCABCCB
思路:就是开个MAP判重,然后广搜到答案输出即可。不会超的。
失误点:弄不对是因为题目按要求的字母序最小的方法。所以按顺序比时只要长度短的更新,长度一样的不用更新。
代码:
/* ID:nealgav1 LANG:C++ PROG:msquare */ #include<fstream> #include<string> #include<cstring> #include<queue> #include<map> using namespace std; ifstream cin("msquare.in"); ofstream cout("msquare.out"); const string mm="12345678"; map<string,string>mp; string taget; string STR; ///A,B,C三种操作 bool A(string a) { string z=a; string b(z.rbegin(),z.rend()); a=b; STR=a; if(mp[a]!="")///如果原先无此量,返回true,入队列 { if(mp[a].length()>mp[z].length()+1)///当长度比其小时更新,一样长不用更新 {mp[a].clear();mp[a]=mp[z]+"A";return true;} else return true; } else if(mp[a]==mm)return true; else {mp[a]=mp[z]+"A";return false;} } bool B(string a) { string z=a; string b; string s(z[3]+z.substr(0,3)+z.substr(5)+z[4]); a=s; STR=a; if(mp[a]!="") { if(mp[a].length()>mp[z].length()+1) {mp[a].clear();mp[a]=mp[z]+"B";return true;} else return true; } else if(mp[a]==mm)return true; else {mp[a]=mp[z]+"B";return false;} } bool C(string a) { string z=a; string b; swap(a[1],a[2]);swap(a[1],a[5]);swap(a[1],a[6]); STR=a; if(mp[a]!="") { if(mp[a].length()>mp[z].length()+1) {mp[a].clear();mp[a]=mp[z]+"C";return true;} else return true; } else if(mp[a]==mm)return true; else {mp[a]=mp[z]+"C";return false;} } void bfs() { string sss="12345678"; queue<string>que; que.push("12345678"); while(!que.empty()) { sss=que.front();///遇到目标输出即可 if(sss==taget)return; que.pop(); if(!A(sss))que.push(STR); if(!B(sss))que.push(STR); if(!C(sss))que.push(STR); } } int main() { string a; for(int i=0;i<8;i++) {cin>>a;taget+=a;} bfs(); cout<<mp[taget].length()<<"\n"; cout<<mp[taget]<<"\n"; cin.close(); cout.close(); }
USER: Neal Gavin Gavin [nealgav1] TASK: msquare LANG: C++ Compiling... Compile: OK Executing... Test 1: TEST OK [0.000 secs, 3408 KB] Test 2: TEST OK [0.000 secs, 3408 KB] Test 3: TEST OK [0.000 secs, 3408 KB] Test 4: TEST OK [0.000 secs, 3408 KB] Test 5: TEST OK [0.097 secs, 4464 KB] Test 6: TEST OK [0.205 secs, 5652 KB] Test 7: TEST OK [0.410 secs, 6972 KB] Test 8: TEST OK [0.616 secs, 7632 KB] All tests OK.YOUR PROGRAM ('msquare') WORKED FIRST TIME! That's fantastic -- and a rare thing. Please accept these special automated congratulations.
Here are the test data inputs:
------- test 1 ---- 2 6 8 4 5 7 3 1 ------- test 2 ---- 1 2 3 4 5 6 7 8 ------- test 3 ---- 6 7 4 1 8 5 2 3 ------- test 4 ---- 5 1 2 4 3 7 8 6 ------- test 5 ---- 6 1 5 4 3 2 7 8 ------- test 6 ---- 4 1 2 3 5 8 7 6 ------- test 7 ---- 3 4 2 1 5 6 7 8 ------- test 8 ---- 4 3 1 2 5 6 7 8Keep up the good work!
Hal Burch
This is a shortest path problem, where the nodes of the graph are board arrangements, and edges are transformations. There are 8! = 40,320 possible board arrangements, so the problem can be solved using breadth-first search (since all edges are of unit length.
Number the boards in increasing order lexicographically, so that indexing is simpler.
In order to simplify the calculations, walk the path backward (start at the ending arrangement given, find the minimum path to the initial configuration following reverse transformations). Then, walk backwards in the resulting tree to determine the path.
#include <stdio.h> #include <assert.h> /* the distance from the initial configuration (+1) */ /* dist == 0 => no know path */ int dist[40320]; /* calculate the index of a board */ int encode(int *board) { static int mult[8] = {1, 8, 8*7, 8*7*6, 8*7*6*5, 8*7*6*5*4, 8*7*6*5*4*3, 8*7*6*5*4*3*2}; /* used to calculate the position of a number within the remaining ones */ int look[8] = {0, 1, 2, 3, 4, 5, 6, 7}; int rlook[8] = {0, 1, 2, 3, 4, 5, 6, 7}; /* rlook[look[p]] = p and look[rlook[p]] = p */ int lv, rv; int t; rv = 0; for (lv = 0; lv < 8; lv++) { t = look[board[lv]]; /* the rank of the board position */ assert(t < 8-lv); /* sanity check */ rv += t * mult[lv]; assert(look[rlook[7-lv]] == 7-lv); /* sanity check */ /* delete t */ look[rlook[7-lv]] = t; rlook[t] = rlook[7-lv]; } return rv; } /* the set of transformations, in order */ static int tforms[3][8] = { {8, 7, 6, 5, 4, 3, 2, 1}, {4, 1, 2, 3, 6, 7, 8, 5}, {1, 7, 2, 4, 5, 3, 6, 8} }; void do_trans(int *inboard, int *outboard, int t) { /* calculate the board (into outboard) that results from doing the t'th transformation to inboard */ int lv; int *tform = tforms[t]; assert(t >= 0 && t < 3); for (lv = 0; lv < 8; lv++) outboard[lv] = inboard[tform[lv]-1]; } void do_rtrans(int *inboard, int *outboard, int t) { /* calculate the board (into outboard) that which would result in inboard if the t'th transformation was applied to it */ int lv; int *tform = tforms[t]; assert(t >= 0 && t < 3); for (lv = 0; lv < 8; lv++) outboard[tform[lv]-1] = inboard[lv]; } /* queue for breadth-first search */ int queue[40325][8]; int qhead, qtail; /* calculate the distance from each board to the ending board */ void do_dist(int *board) { int lv; int t1; int d, t; qhead = 0; qtail = 1; /* the ending board is 0 steps away from itself */ for (lv = 0; lv < 8; lv++) queue[0][lv] = board[lv]; dist[encode(queue[0])] = 1; /* 0 steps (+ 1 offset for dist array) */ while (qhead < qtail) { t1 = encode(queue[qhead]); d = dist[t1]; /* for each transformation */ for (lv = 0; lv < 3; lv++) { /* apply the reverse transformation */ do_rtrans(queue[qhead], queue[qtail], lv); t = encode(queue[qtail]); if (dist[t] == 0) { /* found a new board position! add it to queue */ qtail++; dist[t] = d+1; } } qhead++; } } /* find the path from the initial configuration to the ending board */ void walk(FILE *fout) { int newboard[8]; int cboard[8]; int lv, lv2; int t, d; for (lv = 0; lv < 8; lv++) cboard[lv] = lv; d = dist[encode(cboard)]; /* start at the ending board */ while (d > 1) { for (lv = 0; lv < 3; lv++) { do_trans(cboard, newboard, lv); t = encode(newboard); if (dist[t] == d-1) /* we found the previous board! */ { /* output transformatino */ fprintf (fout, "%c", lv+'A'); /* find the rest of the path */ for (lv2 = 0; lv2 < 8; lv2++) cboard[lv2] = newboard[lv2]; break; } } assert(lv < 3); d--; } fprintf (fout, "\n"); } int main(int argc, char **argv) { FILE *fout, *fin; int board[8]; int lv; if ((fin = fopen("msquare.in", "r")) == NULL) { perror ("fopen fin"); exit(1); } if ((fout = fopen("msquare.out", "w")) == NULL) { perror ("fopen fout"); exit(1); } for (lv = 0; lv < 8; lv++) { fscanf (fin, "%d", &board[lv]); board[lv]--; /* use 0-based instead of 1-based */ } /* calculate the distance from each board to the ending board */ do_dist(board); for (lv = 0; lv < 8; lv++) board[lv] = lv; /* output the distance from and the path from the initial configuration */ fprintf (fout, "%d\n", dist[encode(board)]-1); walk(fout); return 0; }
Thanks for your submission!