搜索—数字三角形

[USACO06FEB] Backward Digit Sums G/S

题面翻译

有这么一个游戏:

写出一个 \(1\sim n\) 的排列 \(a\),然后每次将相邻两个数相加,构成新的序列,再对新序列进行这样的操作,显然每次构成的序列都比上一次的序列长度少 \(1\),直到只剩下一个数字位置。

下面是一个例子:

  • \(3,1,2,4\)
  • \(4,3,6\)
  • \(7,9\)
  • \(16\)

最后得到 \(16\) 这样一个数字。

现在想要倒着玩这样一个游戏,如果知道 \(n\),以及最后得到的数字的大小 \(sum\),请你求出最初序列 \(a_i\)(应该是一个 \(1\sim n\) 的排列)。若答案有多种可能,则输出字典序最小的那一个。

我们称序列 \(a=\lang a_1,a_2,\cdots,a_n\rang\) 的字典序小于序列 \(b=\lang b_1,b_2,\cdots,b_n\rang\) 的字典序,当且仅当存在一个位置 \(p\),满足 \(a_1=b_1,a_2=b_2,\cdots,a_{p-1}=b_{p-1},a_p<b_p\)

题目描述

FJ and his cows enjoy playing a mental game. They write down the numbers from \(1\) to$ N(1 \le N \le 10)$ in a certain order and then sum adjacent numbers to produce a new list with one fewer number. They repeat this until only a single number is left. For example, one instance of the game (when \(N=4\)) might go like this:

    3   1   2   4
      4   3   6
        7   9
         16

Behind FJ's back, the cows have started playing a more difficult game, in which they try to determine the starting sequence from only the final total and the number \(N\). Unfortunately, the game is a bit above FJ's mental arithmetic capabilities.

Write a program to help FJ play the game and keep up with the cows.

输入格式

共一行两个正整数 \(n,sum\)

输出格式

输出包括一行,为字典序最小的那个答案。

当无解的时候,请什么也不输出。

样例 #1

样例输入 #1

4 16

样例输出 #1

3 1 2 4

分析

借助杨辉三角,我们可以通过公式直接预处理,对某个排列三角形求和,如果前面几个的和大于sum,就直接跳过后面的排列,以达到剪枝的目的,借助next_permutation()函数实现全排列。

提示

  • 对于 \(40\%\) 的数据,\(1\le n\le 7\)
  • 对于 \(80\%\) 的数据,\(1\le n \le 10\)
  • 对于 \(100\%\) 的数据,\(1\le n \le 12\)\(1\le sum\le 12345\)

代码实现

#include <bits/stdc++.h>
using namespace std;
int tr[15][15];
int ans[15] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14};
int vis[15];
int n,sum;
void tritriangle()
{
	tr[1][1] = 1;
	for(int i = 2;i <= 12;i ++)	
		for(int j = 1;j <= i;j++){
			tr[i][j] = tr[i-1][j-1] + tr[i-1][j];
		}

}
void slove(){
	do{
		int now = 0;
		for(int i = 1;i <= n;i ++){
			now += tr[n][i] * ans[i];
			if(now > sum){
			sort(ans + i,ans + n + 1,greater<int>());
			i = n;
		}
	}
		if(now > sum)
			continue;
		if(now==sum){
			for(int i = 1;i <= n;i ++)
			{
				cout<<ans[i]<<" ";
			}
			return;
	}

	}while(next_permutation(ans+1,ans+n+1));

}
int main()
{
	cin>>n>>sum;
	tritriangle();
	slove();
	return 0;
}
posted @ 2023-08-21 02:31  LongDz  阅读(33)  评论(0)    收藏  举报