1. 程式人生 > >翻幣問題【廣搜】

翻幣問題【廣搜】

> Description 有N個硬幣(6<=N<=20000)全部正面朝上排成一排,每次將其中5個硬幣翻過來放在原位置,直到最後全部硬幣翻成反面朝上為止。試程式設計找出步數最少的翻法,輸出最少步數及翻法。

> Input 從鍵盤輸入一個正整數N(6<=N<=20000),表示硬幣的數量。

> Output 一個整數,表示最少步數。

> Sample Input 6 (開始:6個硬幣正面朝上)

> Sample Output 6 (最少用6步實現全部反面朝上)

> 解題思路 再說一句這一題又跟電子老鼠闖迷宮電子老鼠闖迷宮

有點像。。。沒辦法就是這麼懶,反正都是廣搜嘛。

就是這一題不再是走路線了,而是翻幣。其實翻幣也只有6個方法:把0個正面的翻過去,5個反面的翻過來;1個正面翻過去,4個反面的翻過來……5個正面的翻過去,0個正面的翻過來。 (i從0列舉到5,表示翻的正面的個數,同樣的,翻的反面的個數就是5-i)所以我就把 a[翻了以後正面的個數] 標記這個正面的個數是否翻過。 s跟之前一樣,也是記錄狀態,但是這裡的 s[maxn*maxn][2] 後面的[0]存正面的個數,[1]存反面的個數。 f也還是存父結點。 就是要注意如何計算正面和負面的個數(表示在這裡改了超級久。。。)

> 程式碼

#include<iostream>
#include<cstdio> using namespace std; const int maxn=200; int a[maxn*maxn]={0},s[maxn*maxn][2]; int f[maxn*maxn]; int n,len=0; bool aka(int i,int h) { if(i>s[h][0]) return false; if(5-i>s[h][1]) return false; if(a[s[h][0]-i+5-i]==1) return false; return true; } void ooo(int m) { if
(m==1) return; len++; ooo(f[m]); } void lil() { int h=0,t=1; f[1]=0; a[n]=1; s[1][0]=n; s[1][1]=0; do { h++; for(int i=0;i<=5;i++) { if(aka(i,h)) { t++; a[s[h][0]-i+5-i]=1; s[t][0]=s[h][0]-i; s[t][1]=s[h][1]+i; s[t][1]=s[t][1]-(5-i); s[t][0]=s[t][0]+5-i; f[t]=h; } if(a[0]==1) { ooo(t); printf("%d",len); return; } } }while(h<=t); } int main() { scanf("%d",&n); lil(); return 0; }