简单游戏
题目大意
原本有n个数字,第1,2个相加,第2,3个相加……第n-1,n个相加,由此得出一个长度为n-1的新序列,然后不停重复,最后得出一个t,现在给出一开始的n和t求符合的序列(字典序最小)(多组数据,0 0结束)
样例输入
4 16
3 9
0 0
样例输出
3 1 2 4
1 3 2
对样例解释:
开始排列: 3 1 2 4
第一次操作:3+1=4 1+2=3 2+4=6
得到: 4 3 6
第二次得到: 7 9
最后就是: 16
数据范围限制
数据保证有解。请注意加粗字体!
对于30%的数据,保证该组里的每个N都不超过10。
对于100%的数据,保证有每个N不超过20,且每组数据的个数不超过10。
解题思路
我们可以由题意得出下图,图中代表的是数字相加的次数,可以看出,这是一个杨辉三角,我们可以先求出杨辉三角,再dfs枚举每一个数
三个优化(必打):
1:判断当前总值是否大于t,若大于,退出
2:因为杨辉三角有对称的特性,所以判断a[i]是否大于a[n-i+1],若不大于,退出
3:将剩下的数和杨辉三角剩下可乘的的数排列,将最大的乘最大的,最小的成最小的,得出剩下的数最大的结果,若当前总值+最大的结果<t 那么绝对不可能有结果,就退出,然后将最大的乘最小的,最小的乘最大的,得出最小的结果,若当前总值+最小的结果>t 那么绝对不可能有结果,就退出
#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
int c[25],yh[25][25],p[25],s[25],h[25],n,t,dg;
void dfs(int x,int y)
{
if (x>n&&y==t)
{
dg=1;
return;
}
if (x>n) return;
if (y>=t) return;
int w=0,big=0,small=0;
for (register int i=1;i<=n;i++)
if (!p[i])
{
s[++w]=i;
h[w]=yh[n][x+w-1];
}
sort(h+1,h+1+w);
for (register int i=1,j=w;i<=w;i++,j--)
{
small+=s[i]*h[j];
big+=s[i]*h[i];
}
if (y+big<t) return;
if (y+small>t) return;
for (register int i=1;i<=n;i++)
if (!p[i])
{
if (x>n/2&&i<=c[n-x+1]) continue;
c[x]=i;
p[i]=1;
dfs(x+1,i*yh[n][x]+y);
p[i]=0;
if (dg) return;
c[x]=0;
}
}
int main()
{
yh[1][1]=1;
for (register int i=2;i<=20;i++)
for (register int j=1;j<=i;j++)
yh[i][j]=yh[i-1][j-1]+yh[i-1][j];
scanf("%d %d",&n,&t);
while(n||t)
{
dg=0;
memset(c,0,sizeof(c));
dfs(1,0);
for (int i=1;i<=n;i++)
printf("%d ",c[i]);
printf("\n");
scanf("%d %d",&n,&t);
}
return 0;
}