宝石排列问题
西安交大 軟件53 ?蔡少斐
題號:5_10
題目敘述:
現有n種不同形狀的寶石,每種n顆,共n*n顆。同一形狀的n顆寶石分別具有n種不同的顏色c1,c2,…,cn中的一種顏色。欲將這n*n顆寶石排列成n行n列的一個方陣,使方陣中每一行和每一列的寶石都有n種不同的形狀和n種不同顏色。是設計一個算法,計算出對于給定的n,有多少種不同的寶石排列方案。
輸入數據:
只有一個整數n
輸出數據:
一個整數,代表不同的寶石排列方案。
題目解答:
?????? 問題將采用回溯法解決,首先搜索其所有的解空間,并生成解空間樹,將滿足條件的情況記錄下來。
?????? 由于要求每一行寶石的形狀和顏色均不相同,因此我們可以從行開始,生成行的有效全排列,然后對剛生的位置進行列有效判定,如果成功則繼續向下搜索,不成功則重新生成排列,繼續判定。
?????? 實現細節:在行進行生成2個排列的時候,先生成形狀的排列,然后對形狀進行列有效判定,若成功則進一步生成行顏色排列,并對顏色進行列有效判定。若都成功,那么這一顆石子也就確定了,則檢驗該石子是否在以前出現過,若出現過則放置失敗,繼續進行同級搜索,否則的話,我們就該考慮向下一個位置的搜索了。
?????? 下一個位置的確定有3種情況,第一種是如果當前位置為(n,n)那么不繼續進行搜索,而是Ans++。第二種情況是如果當前位置為(x,n)那么下一個搜索的位置就是(x+1,1)。
另外,在進行列有效判定時,采用了std::set數據結構進行輔助設計,可以加速判定。
代碼實現:
#include<iostream> #include<algorithm> #include<cstdio> #include<set> usingnamespace std; int used[10][10]; int shapes[10][10]; int colors[10][10]; set<int> col_c[10]; set<int> col_s[10]; int n; int cnt = 0; int dfs(int x, int y ) {int f = 0;for ( int i = y; i <= n; i++ ){swap( shapes[x][i], shapes[x][y]);if ( col_s[y].count( shapes[x][y]) == 0 ){col_s[y].insert(shapes[x][y] );for ( int j = y; j <= n;j++ ){swap( colors[x][j],colors[x][y] );if ( col_c[y].count(colors[x][y] ) == 0 ){col_c[y].insert(colors[x][y] );if (!used[shapes[x][y]][colors[x][y]] ){used[shapes[x][y]][colors[x][y]] = 1;f = 1;if ( x== n && y == n ){++cnt;}else {if( y == n ){dfs(x + 1, 1 );}else {dfs(x, y + 1 );}}used[shapes[x][y]][colors[x][y]]= 0;}col_c[y].erase(colors[x][y] );}swap( colors[x][j],colors[x][y] );}col_s[y].erase(shapes[x][y] );}swap( shapes[x][i], shapes[x][y]);}return(f); }int main() {cin >> n;for ( int x = 1; x <= 9; x++ )for ( int i = 1; i <= 9; i++ ){shapes[x][i] = colors[x][i]= i;}dfs( 1, 1 );cout << "答案:" << cnt<< endl;return(0); }運行結果:
總結