Description
Charles和sunny在玩一个简单的游戏。若给出1~n的一个排列A,则将A1、A2相加,A2、A3相加……An-1、An相加,则得到一组n-1个元素的数列B;再将B1、B2相加,B2、B3相加,Bn-2、Bn-1相加,则得到一组n-2个元素的数列……如此往复,最终会得出一个数T。而Charles和sunny玩的游戏便是,Charles给出n和T,sunny在尽可能短的时间内,找到能通过上述操作得到T且字典序最小的1~n的排列。(sunny大声说:“What an easy game!”,接着几下就给出了解),Charles觉得没意思,就想和你玩,当然,你可以用一种叫做“电子计算机”的东西帮你。
本题有多组数据,对于每组数据:一行两个整数n(0< n<=20),t即最后求出来的数。两个0表示输入结束。
Output
对于每组测试数据输出一行n个整数,用空格分开,行尾无多余空格,表示求出来的满足要求的1~n的一个排列。
4 16
3 9
0 0
Sample Output
3 1 2 4
1 3 2
Data Constraint
对于30%的数据,保证该组里的每个N都不超过10。
对于100%的数据,保证有每个N不超过20,且每组数据的个数不超过10。
Solution
可以通过观察发现,t是由这个n的排列的每个数乘上一个系数得到,系数是杨辉三角第n行。
若直接dfs,就会超时,所以需要剪枝。
1.若已经找到答案,结束dfs
2.若当前的和加上后面能算出的最大值仍小于t,返回上层。
3.若当前的和加上后面能算出的最小值仍大于t,返回上层。
4.由于系数对称,而要找字典序最小的序列,所以,当系数相同时,小的数一定在前面。
using namespace std;
int f[N][N];
int q[N] ,t[N],x [N];
int n,m ;
bool b;
void pre()
{
memset(f,0 ,sizeof(f));
f[1 ][1 ]=1 ;
for (int i=2 ;i<N;++i)
for (int j=1 ;j<=i;++j)
f[i][j]=f[i-1 ][j-1 ]+f[i-1 ][j];
}
bool comp(int x ,int y )
{
return x >y ;
}
bool pd(int dep,int s )
{
int an=s ;
for (int i=dep;i<=n;++i)
x [i-dep]=f[n][i];
sort (x ,x +n-dep+1 ,comp);
/*for (int i=0;i<=n-dep;++i)
printf("%d ",x[i]);
printf("\n");*/
int j=0 ;
for (int i=n;i>=1 ;--i)
if (t[i]==0 )
{
an+=i*x [j];
j++;
}
//printf ("max=%d \n" ,an);
if (an<m ) return true;
an=s ;
j=0 ;
for (int i=1 ;i<=n;++i)
if (t[i]==0 )
{
an+=i*x [j];
j++;
}
//printf ("min=%d \n" ,an);
if (an>m ) return true;
return false;
}
void dfs(int dep,int s )
{
/*printf("%d,%d\n",dep,s);
for (int i=1;i<=n;++i)
printf("%d ",t[i]);
printf("\n");*/
if (b==1 ) return ;
if (dep==n)
{
if (s ==m )
{
for (int i=1 ;i<=n;++i)
printf ("%d " ,q[i] );
printf ("\n" );
b=1 ;
}
return ;
}
if (s >m ) return ;
if (pd(dep+1 ,s )) return ;
if (dep>n/2 && q[dep] <q[n-dep+1] ) return ;
for (int i=1 ;i<=n;++i)
if (t[i]==0 )
{
t[i]=1 ;
q[dep+1] =i;
dfs(dep+1 ,s +i*f [n][dep+1 ]);
t[i]=0 ;
}
}
int main()
{
freopen("easy.in" ,"r" ,stdin);
freopen("easy.out" ,"w" ,stdout);
pre();
scanf("%d %d " ,&n,&m );
while (not (n==0 && m ==0 ))
{
b=0 ;
memset(t,0 ,sizeof(t));
dfs(0 ,0 );
scanf("%d %d " ,&n,&m );
}
return 0 ;
}