翻幣問題【廣搜】
阿新 • • 發佈:2018-12-09
> 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;
}