洛谷OJ P1118 数字三角形游戏 解题报告
洛谷OJ P1118 数字三角形游戏 解题报告
by MedalPluS
题目描述
有这么一个游戏:
写出一个1~N的排列a[i],然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少1,直到只剩下一个数字位置。下面是一个例子:
3 1 2 4
4 3 6
7 9
16
最后得到16这样一个数字。
现在想要倒着玩这样一个游戏,如果知道N,知道最后得到的数字的大小sum,请你求出最初序列a[i],为1~N的一个排列。若答案有多种可能,则输出字典序最小的那一个。
输入格式
两个正整数n,sum
输出格式
输出包括1行,为字典序最小的那个答案
规模
对于40%的数据,n≤7;
对于80%的数据,n≤10;
对于100%的数据,n≤12,sum≤12345,且保证一定有解。
分析
拿到题目就有一种暴搜的想法,我们枚举1~n的全排列,然后逐个试
结果就TLE了。。60分
然后想了想,每次试的时候n2有点耗时,然后又发现对于第1层的数=∑ai*cni (ai表示枚举的数列 cij表示杨辉三角第n行第i列)
然后还是TLE了。。80分
觉得STL太慢了,手写了个DFS,再加了个可行性剪枝
结果居然WA90了。。
发现杨辉三角写挫了。。
要自责。。。
代码
1 #include <iostream> 2 #include <cstdio> 3 #include <cstdlib> 4 #include <cstring> 5 using namespace std; 6 7 const int maxn=13; 8 9 int a[maxn],c[maxn][maxn],n,sum; 10 bool used[maxn]; 11 12 void dfs(int i,int sum){ 13 if(sum<0)return; 14 if(i>n){ 15 if(sum>0)return; 16 for(int j=1;j<=n;j++)printf("%d ",a[j]); 17 exit(0); 18 } 19 for(int j=1;j<=n;j++) 20 if(!used[j]){ 21 used[j]=true; 22 a[i]=j; 23 dfs(i+1,sum-j*c[n][i]); 24 used[j]=false; 25 } 26 } 27 28 int main(){ 29 cin>>n>>sum; 30 int i,j,res=0; 31 for(i=1;i<=n;i++)a[i]=i; 32 for(i=1;i<=n;i++)c[i][i]=c[i][1]=1; 33 for(i=3;i<=n;i++) 34 for(j=2;j<=i;j++) 35 c[i][j]=c[i-1][j]+c[i-1][j-1]; 36 memset(used,false,sizeof(used)); 37 dfs(1,sum); 38 return 0; 39 }