標籤:
Magic Squares
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:
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:
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: msquareINPUT 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)
7BCABCCB
題意:一塊模板有三種操作:分別是A、B、C,A操作時交換上下兩行,B操作時將最後一列插在最前面,C操作時將中間四個數順時針旋轉一下。告訴你初始狀態和目標狀態,求最少多少次操作可以變化到目標狀態,並且輸出其操作序列。輸入的目標狀態時按順時針輸入的。
思路:
就是 BFS咯。
對於判重 下面用的是map直接暴力判斷。另外一種way就是 康托展開 得到一個Hash值。
看這個值出現過沒有就OK了。
用康托展開 不僅把空間縮小到了 n!(n為字串長度,這裡是8) 而且還很快也。
推薦~
至於康托展開:
X=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0! ,(其中a[i]為當前未出現的元素中是排在第幾個(從0開始))(網上十分複雜的說法)
(其實就是 比當前位置的數 小&&未出現過 的數 一共有多少個)(實質就是 在全排列中 比當前排列小的一共有多少個 )。這就是康托展開。 (將Hash值+1 就是這個排列自己的序號了(是第幾小)(從1開始))
Contor 代碼:
const int FRAC[MSQUARE_SIZE]= {1, 1, 2, 6, 24, 120, 720, 5040};//這個數組儲存的是 各個上述的 階層
//此處預設字串長度就是8
inline int Contor(string &v){ int ans = 0; for (int i = 0; i < 8; i++) { int tmp = 0; for (int j = i+1; j < 8; j++) if (v[i] > v[j]) ++tmp;
//統計比當前位置的數 小&&未出現過的數 有多少個。
//當然也就等於 在當前位置後面 比當前位置的數 小的數的個數
ans += tmp * FRAC[7-i]; } return ans+1;}
下面是題目代碼 :
/*ID:Andy ChenLANG: C++PROG: msquare*/#include<iostream>#include<cstdio>#include<queue>#include<string>#include<map>#define MAXN 10000using namespace std;struct state{ string s,ans; int step;};char ans[MAXN];map<string,bool> vis;string tail;string opA(string a){ int i; for(i=0;i<4;i++) swap(a[i],a[i+4]); return a;}string opB(string a){ char t; t=a[3];a[3]=a[2];a[2]=a[1];a[1]=a[0];a[0]=t; t=a[7];a[7]=a[6];a[6]=a[5];a[5]=a[4];a[4]=t; return a;}string opC(string a){ char t; t=a[1];a[1]=a[5];a[5]=a[6];a[6]=a[2];a[2]=t; return a;}void BFS(){ bool flag; state t,tt; t.step=0;t.s="12348765";t.ans=""; queue<state>Q; Q.push(t); vis[t.s]=true; while(!Q.empty())//以下的vis 可以替換為 康托展開的Hash值.判斷 { t=Q.front();Q.pop(); if(t.s==tail) { cout<<t.step<<endl<<t.ans<<endl; return ; } tt.ans=t.ans; tt.step=t.step+1; flag=false; tt.s=opA(t.s); if(!vis[tt.s]) { vis[tt.s]=true; tt.ans+=‘A‘; Q.push(tt); flag=true; } tt.s=opB(t.s); if(!vis[tt.s]) { vis[tt.s]=true; if(!flag) tt.ans+=‘B‘; else tt.ans[t.step]=‘B‘; Q.push(tt); flag=true; } tt.s=opC(t.s); if(!vis[tt.s]) { vis[tt.s]=true; if(!flag) tt.ans+=‘C‘; else tt.ans[t.step]=‘C‘; Q.push(tt); } }}int main(){ freopen("msquare.in","r",stdin); freopen("msquare.out","w",stdout); int i; string t; for(i=1;i<=8;i++) { cin>>t;tail+=t; } swap(tail[4],tail[7]); swap(tail[5],tail[6]);//因為是順時針輸入,所以需要手動交換一下位置。 BFS(); return 0;}
Feed Ratios(康托展開 )