51nod 1800 漢諾塔

LYK最近在研究漢諾塔問題。
漢諾塔(又稱河內塔)問題是源於印度一個古老傳說的益智玩具。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞着64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
在這個問題中,黃金圓盤的數量從原來的64片變成了n片。
大家都知道對於n片圓盤的漢諾塔問題的最少操作次數是2^n-1次。
現在LYK將初始時的n片圓盤按照規則隨機擺放(也就是說每片圓盤一開始可能在3根柱子上的任意一根,且小圓盤上沒有大圓盤),共有3^n擺法。
LYK想將所有圓盤都重新擺放進第三根柱子。
當然最優方案顯然是唯一的。
請你求出這3^n種不同的初始狀態中,存在幾種使得最少操作次數恰好等於m。

在樣例中,共有2片圓盤,擺放狀態共有9種,只有當大圓盤在第3根柱子,小圓盤在第1或者第2根柱子時,最少操作次數恰好等於1。因此答案爲2。
Input
一行兩個整數n,m(1<=n,m<10^100)。
Output
一行表示答案
Input示例
2 1
Output示例
2
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

高精度+DP+神奇的思路~

花了我六十……好心疼啊QAQ

我們用f[i][j]表示j個圓盤,用i步的方案數,那麼

當i在第三根柱子上時,=f[i-1][j];

其餘情況,我們把所有小於它的圓盤移到1或2柱子上,移動i後,再用(2^(i-1)-1)步移回來,=f[i-1][j-2^(i-1)]。

所以f[i][j]=f[i-1][j]+f[i-1][j-2^(i-1)]*2。

觀察到n<=10^100,n趨於無窮大,這時i和i-1近似相等,我們發現第一維可以忽略,f[j]=2^(n中1的個數)。

所以我們用高精度求一下這個值就好了……

要注意特判0的情況。


#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;

int n,m,a[1001],f[1001],tot,cnt;
char s[1001],s1[1001];

int cal()
{
	int tot=0;
	for(int i=0;i<n;i++) tot=tot*10+s1[i]-'0';
	return tot;
}

int main()
{
	scanf("%s%s",s1,s);
	n=strlen(s);
	for(int i=0;i<n;i++) a[n-i]=s[i]-'0';
	f[1]=tot=1;
	for(;n>1 || a[1];cnt++)
	{
		if(a[1]&1)
		{
			for(int i=1;i<=tot;i++) f[i]*=2;
			for(int i=1;i<=tot;i++) if(f[i]>9) f[i+1]++,f[i]-=10;
			if(f[tot+1]) tot++;
		}
		for(int i=n,z=0;i;i--) z=z*10+a[i],a[i]=z>>1,z&=1;
		if(!a[n]) n--;
	}
	n=strlen(s1);
	if(n<=3 && cnt>cal()) puts("0");
	else for(int i=tot;i;i--) printf("%c",f[i]+'0');
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章