《黑书》递推练习题:锁链poj1090、poj1832

这是黑书课后习题锁链......他们都说是递推题目,好吧,我必须得承认可以用递推做,只是我不明白他们怎么推的,现在我说说我的做法:

首先,需要看一看《九连环与格雷码不得不说的故事》(这是我转载的):

分析解九连环的完全记法,由于每次只动一个环,故两步的表示也只有一个数字不同。下面以五个环为例分析。左边起第一列的五位数是5个环的状态,依次由第一环到第五环。第二列是把这个表示反转次序的五位数,似乎是二进制数,但是与第四列比较就可以看出这不是步数的二进制数表示。 

第三列是从初始状态到这个状态所用的步数。最右边一列才是步数的二进制表示。

  0000000000000000

  1000000001100001

  1100000011200010

  0100000010300011

  0110000110400100

  1110000111500101

  1010000101600110

  0010000100700111

  0011001100801000

  1011001101901001

  11110011111001010

  01110011101101011

  01010010101201100

  11010010111301101

  10010010011401110

  00010010001501111

  00011110001610000

  10011110011710001

  11011110111810010

  01011110101910011

  01111111102010100

  11111111112110101

  我们发现,右边一列数恰好是十进制数021的二进制数的格雷码! 这当然需要21步。如果把5位二进制数依次写完,就是

  10111111012210110

  00111111002310111

  00101101002411000

  10101101012511001

  11101101112611010

  01101101102711011

  01001100102811100

  11001100112911101

  10001100013011110

  00001100003111111

  这说明,对于只有5个环的五连环,从初始到状态11111用的不是并不是最多,到状态00001才是最多,用31步。类似,对于九连环,从初始到状态111111111用的不是并不是最多,到状态000000001才是最多,用511步。由于格雷码111111111表示二进制数101010101,表示十进制数341,故从初始状态到9个环全部上去用341步。这就是九连环中蕴涵的数学内涵。

  注 由二进制数转换为格雷码:从右到左检查,如果某一数字左边是0,该数字不变;如果是1,该数字改变(0变为11变为0)。例,二进制数11011的格雷码是10110.

  由格雷码表示变为二进制数:从右到左检查,如果某一数字的左边数字和是偶数,该数字不变;如果是奇数,该数字改变。

  例 格雷码11011表示为二进制数是10010.

  以上可以用口诀帮助记忆:2G一改零不改,G2奇变偶不变。

  例 设九连环的初始状态是110100110,要求终止状态是001001111,简单解法与完整解法各需要多少步?过程如何?

  解 初始状态110100110,格雷码是011001011,转换为二进制数是010001101,相应十进制数是141.终止状态是001001111,格雷码是111100100,转换为二进制数是101000111,相应十进制数是327.二者差326141186,完整解法需要186步。

 

看完后,我发现所有的九连环问题都不是问题了,有木有??......我是直接模拟过的,做完这道,还有poj1832,也是九连环问题,可以随意练练受,记得要注意一步也不用走的状态哦.......
poj1090:

#include<iostream>

#include<stdio.h>

#include<string.h>

#include<algorithm>

using namespace std;

int s[10000],t[1005],f[1005][400];

int main()

{

	int n;

	scanf("%d",&n);

	

	int sum=0;

	for(int i=n;i>=1;i--)

	{

		scanf("%d",&s[i]);

		sum+=s[i];

	}

	for(int i=n;i>=1;i--)

	{

		sum-=s[i];

		if(sum%2==0)

		continue;

		else

		{

			if(s[i]==1)

			s[i]=0;

			else

			s[i]=1;

		}

	}

	memset(t,0,sizeof(t));

	memset(f,0,sizeof(f));

	f[1][399]=1;

	for(int i=2;i<=1000;i++)

	{

		for(int k=399;k>=1;k--)

		{

			f[i][k]=f[i-1][k]*2;	

		}

		for(int k=399;k>=1;k--)

		if(f[i][k]>9)

		{

			f[i][k-1]+=f[i][k]/10;

			f[i][k]%=10;

		}	

	}

	for(int i=n,j=1;i>=1;i--,j++)

	{

		if(s[i]==1)

		{

			for(int k=399;k>=1;k--)

			{

				t[k]+=f[j][k];

				if(t[k]>9)

				{

					t[k-1]+=t[k]/10;

					t[k]%=10;

				}

			}

		}

	}

	for(int tmp=399;tmp>=1;tmp--)

	if(t[tmp]>9)

	{

		t[tmp-1]+=t[tmp]/10;

		t[tmp]%=10;

	}

	int i;

	for(i=1;i<=399;i++)

	if(t[i]!=0)

	break;

	if(i>399)

	{

		printf("0\n");

	}

	else

	{

		for(;i<=399;i++)

		printf("%d",t[i]);

		printf("\n");

	}

	return 0;

} 

 

 poj1832

#include<iostream>

#include<stdio.h>

#include<math.h>

#include<string.h>

using namespace std;

int s[1000],t[1000],f[200][200],ht[200],hs[200];

char str[2][205];

int main()

{

	int text;

	scanf("%d",&text);

	memset(f,0,sizeof(f));

	f[1][199]=1;

	for(int i=2;i<=128;i++)

	{

		for(int j=199;j>=1;j--)

		{

			f[i][j]=f[i-1][j]*2;

		}

		for(int j=199;j>=1;j--)

		if(f[i][j]>9)

		{

			f[i][j-1]+=f[i][j]/10;

			f[i][j]%=10;

		}

	}

	/*for(int i=1;i<=128;i++)

	{

		int j=1;

		while(f[i][j]==0)

		j++;

		for(;j<=199;j++)

		printf("%d",f[i][j]);

		printf("\n");

	}*/

	while(text--)

	{

		int n;

		scanf("%d",&n);

		int sums=0,sumt=0;

		for(int i=1;i<=n;i++)

		{

			scanf("%d",&s[i]);

			sums+=s[i];

		}

		for(int i=1;i<=n;i++)

		{

			scanf("%d",&t[i]);

			sumt+=t[i];

		}

		for(int i=n;i>=1;i--)

		{

			sums-=s[i];

			sumt-=t[i];

			if(sums%2==1)

			{

				if(s[i]==1)

				s[i]=0;

				else

				s[i]=1;

			}

			if(sumt%2==1)

			{

				if(t[i]==1)

				t[i]=0;

				else

				t[i]=1;

			}

		}

		memset(ht,0,sizeof(ht));

		memset(hs,0,sizeof(hs));

		for(int i=n,j=1;i>=1;i--,j++)

		{

			if(s[i]==1)

			{

				for(int k=199;k>=1;k--)

				{

					hs[k]+=f[j][k];

					if(hs[k]>9)

					{

						hs[k-1]+=hs[k]/10;

						hs[k]%=10;

					}

				}

			}

			if(t[i]==1)

			{

				for(int k=199;k>=1;k--)

				{

					ht[k]+=f[j][k];

					if(ht[k]>9)

					{

						ht[k-1]+=ht[k]/10;

						ht[k]%=10;

					}

				}

			}

		}

		for(int k=199;k>=1;k--)

		{

			if(hs[k]>9)

			{

				hs[k-1]+=hs[k]/10;

				hs[k]%=10;

			}

			if(ht[k]>9)

			{

				ht[k-1]+=ht[k]/10;

				ht[k]%=10;

			}

		}

		int w=0;

		memset(str,0,sizeof(str));

		str[0][0]=str[1][0]='0';

		for(int i=1;i<=199;i++)

		{

			str[0][i-1]=hs[i]+'0';

			str[1][i-1]='0'+ht[i];

		}

		/*

		int i;

		for( i=1;i<=199;i++)

		if(hs[i]!=0)

		break;

		for(;i<=199;i++)

		printf("%d",hs[i]);

		printf("\n");

		for(i=1;i<=199;i++)

		if(ht[i]!=0)

		break;

		for(;i<=199;i++)

		printf("%d",ht[i]);

		printf("\n");

		

		printf("%d\n",strcmp(str[0],str[1]));

		*/

		if(strcmp(str[0],str[1])>0)

		{

			for(int k=199;k>=1;k--)

			hs[k]-=ht[k];

			for(int k=199;k>=1;k--)

			if(hs[k]<0)

			{

				hs[k-1]--;

				hs[k]+=10;

			}

		}

		else

		{

			for(int k=199;k>=1;k--)

			ht[k]-=hs[k];

			for(int k=199;k>=1;k--)

			if(ht[k]<0)

			{

				ht[k-1]--;

				ht[k]+=10;

			}

			w=1;

		}

		if(w==0)

		{

			int i;

			for(i=1;i<=199;i++)

			if(hs[i]!=0)

			break;

			for(;i<=198;i++)

			printf("%d",hs[i]);

			printf("%d\n",hs[i]);

		}

		else

		{

			int i;

			for(i=1;i<=199;i++)

			if(ht[i]!=0)

			break;

			for(;i<=198;i++)

			printf("%d",ht[i]);

			printf("%d\n",ht[i]);

		}

	}

	return 0;

}

 

 

你可能感兴趣的:(poj)