黑书257页例题有木有啊
别人几句话就说完了有木有啊
完全看不懂有木有啊
没办法只好上网搜题解啊
题解也看了半天啊
//我无奈了,,
努力了很久还是没写出来。不过总算理解了。。。
这是努力的结果~
#include<iostream>
#include<stdlib.h>
using namespace std;
__int64 W[21][21],M[21][21],c;
int used[21],num[21],link[21],list[21],n;
__int64 getDown (int x, int n);
__int64 getUp (int x, int n);
__int64 getDown (int x, int n)
{
if ( W[x][n] != -1 ) return W[x][n];
__int64 ans=0;
for (int i=1; i<x; i++) ans+= getUp (i, n-1);
return ( W[x][n] = ans );
}
__int64 getUp (int x, int n)
{
if ( M[x][n] != -1 ) return M[x][n];
return ( M[x][n] = getDown(n-x+1, n) );
}
void Init()
{
int i, j;
memset(W, -1, sizeof(W));
memset(M, -1, sizeof(M));
for (i=1; i<=20; i++) W[1][i] = 0;
W[2][2] =M[1][2] =M[1][1] =W[1][1] = 1;
M[2][2] =W[1][2] = 0;
for (i=3; i<=20; i++)
{
for (j=1; j<=i; j++)
{
getDown(j, i);
getUp(j, i);
}
}
}
int main()
{
int T,i,j,len,down;
scanf("%d",&T);
Init();
// for(i=1;i<=3;i++) printf("%I64d %I64d\n",W[i][3],M[i][3]);
while(T--)
{
scanf("%d%I64d", &n, &c);
for(i=1;i<=n;i++) printf("%I64d %I64d\n",W[i][n],M[i][n]);
memset(used,0,sizeof(used));
for(i=1;i<=20;i++) num[i]=i;
i=1;down=1;len=0;
while(n>0)
{
// if(i>n) i=1;
if(1==used[i])
{
i++;
continue;
}
for(int k=1;k<=4;k++) printf("%d ",num[k]);printf("\n");
printf("%d%d %I64d %I64d down=%d i=%d n=%d c=%I64d\n",num[i],n,W[num[i]][n],M[num[i]][n],down,i,n,c);
system("pause");
if(down)
{ printf("W\n");
if(c>W[num[i]][n])
{
down=!down;
c-=W[num[i]][n];
}
else
{printf("!\n");
list[++len]=i;
for(j=i+1;j<=n;j++)
{
num[j]--;
}
used[i]=1;
i=1;
down=!down;
n--;
}
}
else
{printf("M\n");
if(c>M[num[i]][n])
{
down=!down;
c-=M[num[i]][n];
i++;
}
else
{printf("!\n");
list[++len]=i;
for(j=i+1;j<=n;j++)
{
num[j]--;
// printf("~");
}//printf("-%d %d-\n",i,n);
down=!down;
n--;
used[i]=1;
}
}
}printf("len=%d\n",len);
for(i=1;i<len;i++)
printf("%d ",list[i]);printf("%d\n",list[len]);
}
}//wrong
AC代码和注释
#include<iostream>
#include<cstdio>
#include<stdlib.h>
using namespace std;
__int64 W[21][21],M[21][21],c;
int used[21],n;
__int64 getDown (int x, int n);
__int64 getUp (int x, int n);
__int64 getDown (int x, int n)
{
if ( W[x][n] != -1 ) return W[x][n];
__int64 ans=0;
for (int i=1; i<x; i++) ans+= getUp (i, n-1);
return ( W[x][n] = ans );
}
__int64 getUp (int x, int n)
{
if ( M[x][n] != -1 ) return M[x][n];
return ( M[x][n] = getDown(n-x+1, n) );
}
void Init()
{
int i, j;
memset(W, -1, sizeof(W));
memset(M, -1, sizeof(M));
for (i=1; i<=20; i++) W[1][i] = 0;
W[2][2] =M[1][2] =M[1][1] =W[1][1] = 1;
M[2][2] =W[1][2] = 0;
for (i=3; i<=20; i++)
for (j=1; j<=i; j++)
{
getDown(j, i);
getUp(j, i);
}
}
void Output (int x, int k)
{
int i;
do
{
for (i=1; i<=k; i++)
{
//若1~k中有以前已确定的木条,并且x木条比已确定的木
//条长度要长,那么x木条的长度应加1
if ( used[i] && x >= i )
{
x++;
k++;
}
}
}while ( used[x] );
if ( k > 1 ) printf("%d ", x);
else printf("%d", x);
used[x] = 1;
}
void Solve ()
{
int up=1, i=1, first=1;
memset(used, 0, sizeof(used));
//Question: 为什么不是从W开始,up=0?
//Answer: 所有的W[1][i]都等于0, up=0的操作没有意义。
while ( n > 0 )
{
if ( up == 1 )
{
if ( c > M[i][n] )
{
if ( first ) //是否是在查找第1根木条
up = !up; //只有在查找第一个木条时需要翻转
//假设第一个是在M中找到的,那么第二个一定是在W中遍历找到的
c -= M[i][n];
i++;
}
else
{
Output(i, n);
first = 0;
//i = 1;←错误 //当前是M型,下一个一定是W型,且开头的数字i大于当前的i ,i+1 ~ n
up = !up;
n--;
}
}
else
{
if ( c > W[i][n] )
{
if ( first ) up = !up;
c -= W[i][n];
if ( !first ) i ++;
}
else
{
Output(i, n);
first = 0;
up = !up;
n--;
i = 1; //下一个i小于当前的i,1 ~ i-1
}
}
}
printf("\n");
}
int main ()
{
int T;
scanf("%d",&T);
Init();
while(T--)
{
scanf("%d%I64d", &n, &c);
Solve();
}
return 0;
}