《黑书》递推练习题:锁链poj1090、poj1832
这是黑书课后习题锁链......他们都说是递推题目,好吧,我必须得承认可以用递推做,只是我不明白他们怎么推的,现在我说说我的做法:
首先,需要看一看《九连环与格雷码不得不说的故事》(这是我转载的):
分析解九连环的完全记法,由于每次只动一个环,故两步的表示也只有一个数字不同。下面以五个环为例分析。左边起第一列的五位数是5个环的状态,依次由第一环到第五环。第二列是把这个表示反转次序的五位数,似乎是二进制数,但是与第四列比较就可以看出这不是步数的二进制数表示。
第三列是从初始状态到这个状态所用的步数。最右边一列才是步数的二进制表示。
00000-00000-0-00000
10000-00001-1-00001
11000-00011-2-00010
01000-00010-3-00011
01100-00110-4-00100
11100-00111-5-00101
10100-00101-6-00110
00100-00100-7-00111
00110-01100-8-01000
10110-01101-9-01001
11110-01111-10-01010
01110-01110-11-01011
01010-01010-12-01100
11010-01011-13-01101
10010-01001-14-01110
00010-01000-15-01111
00011-11000-16-10000
10011-11001-17-10001
11011-11011-18-10010
01011-11010-19-10011
01111-11110-20-10100
11111-11111-21-10101
我们发现,右边一列数恰好是十进制数0到21的二进制数的格雷码! 这当然需要21步。如果把5位二进制数依次写完,就是
10111-11101-22-10110
00111-11100-23-10111
00101-10100-24-11000
10101-10101-25-11001
11101-10111-26-11010
01101-10110-27-11011
01001-10010-28-11100
11001-10011-29-11101
10001-10001-30-11110
00001-10000-31-11111
这说明,对于只有5个环的五连环,从初始到状态11111用的不是并不是最多,到状态00001才是最多,用31步。类似,对于九连环,从初始到状态111111111用的不是并不是最多,到状态000000001才是最多,用511步。由于格雷码111111111表示二进制数101010101,表示十进制数341,故从初始状态到9个环全部上去用341步。这就是九连环中蕴涵的数学内涵。
注 由二进制数转换为格雷码:从右到左检查,如果某一数字左边是0,该数字不变;如果是1,该数字改变(0变为1,1变为0)。例,二进制数11011的格雷码是10110.
由格雷码表示变为二进制数:从右到左检查,如果某一数字的左边数字和是偶数,该数字不变;如果是奇数,该数字改变。
例 格雷码11011表示为二进制数是10010.
以上可以用口诀帮助记忆:2G一改零不改,G2奇变偶不变。
例 设九连环的初始状态是110100110,要求终止状态是001001111,简单解法与完整解法各需要多少步?过程如何?
解 初始状态110100110,格雷码是011001011,转换为二进制数是010001101,相应十进制数是141.终止状态是001001111,格雷码是111100100,转换为二进制数是101000111,相应十进制数是327.二者差326-141=186,完整解法需要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;
}

浙公网安备 33010602011771号