棋盘游戏(信息学奥赛一本通-T1451)
【題目描述】
在一個 4×4 的棋盤上有 8 個黑棋和 8 個白棋,當(dāng)且僅當(dāng)兩個格子有公共邊,這兩個格子上的棋是相鄰的。移動棋子的規(guī)則是交換相鄰兩個棋子。
給出一個初始棋盤和一個最終棋盤,請找出一個最短的移動序列使初始棋盤變?yōu)樽罱K棋盤。
【輸入】
前四行,每行 4 個數(shù)字(1 或者 0 ),描述了初始棋盤;
接著是一個空行;
第六到第九行,每行 4 個數(shù)字(1 或者 0),描述了最終棋盤。
【輸出】
一行是一個整數(shù) n,表示最少的移動步數(shù)。
【輸入樣例】
1111
0000
1110
0010
1010
0101
1010
0101
【輸出樣例】
4
思路:
本題是要從一個大狀態(tài)變到另一個大狀態(tài),并且求其最小步數(shù),很容易看出應(yīng)用 BFS 來做
可以看出,每個單元非 0 即 1,共有 16 個單元,這樣可以將每個棋盤當(dāng)做一個 16 位的二進制數(shù),將其轉(zhuǎn)為十進制后再存儲狀態(tài),最多有 2^16=65535 種狀態(tài)
對于每種狀態(tài),由高到低枚舉每個位置,計算該位置在棋盤上的坐標(biāo) (x,y),理論上來說,格子可與其上下左右相鄰的四個格子任意進行交換,但顯然,但采用異或運算交換兩個相鄰格子時,對每個格子四方向的枚舉互換會造成大量的重復(fù),因此,只要對每個格子從上到下,從左到右去嘗試互換即可
【源程序】
#include<iostream> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<utility> #include<stack> #include<queue> #include<vector> #include<set> #include<map> #include<bitset> #define PI acos(-1.0) #define INF 0x3f3f3f3f #define LL long long #define Pair pair<int,int> LL quickPow(LL a,LL b){ LL res=1; while(b){if(b&1)res*=a; a*=a; b>>=1;} return res; } LL multMod(LL a,LL b,LL mod){ a%=mod; b%=mod; LL res=0; while(b){if(b&1)res=(res+a)%mod; a=(a<<=1)%mod; b>>=1; } return res%mod;} LL quickMultPowMod(LL a, LL b,LL mod){ LL res=1,k=a; while(b){if((b&1))res=multMod(res,k,mod)%mod; k=multMod(k,k,mod)%mod; b>>=1;} return res%mod;} LL quickPowMod(LL a,LL b,LL mod){ LL res=1; while(b){if(b&1)res=(a*res)%mod; a=(a*a)%mod; b>>=1; } return res; } LL getInv(LL a,LL mod){ return quickPowMod(a,mod-2,mod); } LL GCD(LL x,LL y){ return !y?x:GCD(y,x%y); } LL LCM(LL x,LL y){ return x/GCD(x,y)*y; } const double EPS = 1E-6; const int MOD = 1000000000+7; const int N = 1000+5; const int dx[] = {0,0,-1,1,1,-1,1,1}; const int dy[] = {1,-1,0,0,-1,1,-1,1}; using namespace std;struct Node {int val;int step;Node() {}Node(int val, int step) : val(val), step(step) {} }; int vis[65536 + 10]; void BFS(Node st, Node ed) {memset(vis, 0, sizeof(vis));queue<Node> Q;Q.push(st);while (!Q.empty()) {Node now = Q.front();Q.pop();if (now.val == ed.val) {cout << now.step << endl;return;}int val = now.val;int step = now.step;for (int i = 15; i >= 0; i--) { //從高到低枚舉每一位int x = (15 - i) / 4, y = (15 - i) % 4; //橫縱坐標(biāo)int nowPos = 1 << i; //當(dāng)前位置代表權(quán)值int rightPos = 1 << (i - 1); //當(dāng)前位置右方位置代表權(quán)值int downPos = 1 << (i - 4); //當(dāng)前位置下方位置代表權(quán)值if (y < 3 && ((val & nowPos) != (val & rightPos))) { //向右交換int nextVal = val ^ nowPos ^ rightPos; //交換后的狀態(tài)if (!vis[nextVal]) {vis[nextVal] = true;Q.push(Node(nextVal, step + 1));}}if (x < 3 && ((val & nowPos) != (val & downPos))) { //向下交換int nextVal = val ^ nowPos ^ downPos; //交換后的狀態(tài)if (!vis[nextVal]) {vis[nextVal] = true;Q.push(Node(nextVal, step + 1));}}}} } int main() {char ch;int st = 0, ed = 0;for (int i = 15; i >= 0; i--) {cin >> ch;if (ch == '1')st += 1 << i;}for (int i = 15; i >= 0; i--) {cin >> ch;if (ch == '1')ed += 1 << i;}if (st == ed)printf("0\n");elseBFS(Node(st, 0), Node(ed, 0));return 0; }?
新人創(chuàng)作打卡挑戰(zhàn)賽發(fā)博客就能抽獎!定制產(chǎn)品紅包拿不停!總結(jié)
以上是生活随笔為你收集整理的棋盘游戏(信息学奥赛一本通-T1451)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 悼念512汶川大地震遇难同胞——珍惜现在
- 下一篇: 理论基础 —— 栈 —— 双端栈