P1118 [USACO06FEB]Backward Digit Sums G/S
P1118 [USACO06FEB]Backward Digit Sums G/S


题解:
(1)暴力法。对1~N这N个数做从小到大的全排列,对每个全排列进行三角形的计算,判断是否等于N。
对每个排列进行三角形计算,需要O(N2)次。例如第1行有5个数{a,b,c,d,e},那么第2行计算4次,第3行计算3次…等等,总次数是O(N2)的。
a b c d e
a+b b+c c+d d+e
a+2b+c b+2c+d c+2d+e
a+3b+3c+d b+3c+3d+e
a+4b+6c+4d+e
共有N!=4亿个排列,总复杂度是O ( N ! N 2 ) 的,显然会超时。
2)三角计算优化+剪枝。
1)三角计算的优化。对排列进行三角形计算,并不需要按部就班地算,比如{a,b,c,d,e}这5个数,直接算最后一行的公式a+4b+6c+4d+e就好了,复杂度是O(N)的。
不同的N有不同的系数,比如5个数的系数是{1,4,6,4,1},提前算出所有N的系数备用。可以发现,这些系数正好是杨辉三角。
2)剪枝。即使有了杨辉三角的优化,总复杂度还是有O(N!N),所以必须进行最优性剪枝。对某个排列求三角形和时,如果前面几个元素和已经大于sum,
那么后面的元素就不用再算了。例如,N=9时,计算到排列{2,1,3,4,5,6,7,8,9},如果前5个元素{2,1,3,4,5}求和已经大于sum,那么后面的{6,7,8,9}~{9,8,7,6}都可以跳过,
下一个排序从{2,1,3,4,6,5,7,8,9}开始。本题sum≤12345,和不大,用这个简单的剪枝方法可以通过。
3)可以用DFS求全排列,也可以直接用STL 的next_permutation()求全排列。
#include <cstdio>
using namespace std; int n,sum;
//以下所有数组的大小都比所需值稍大,是为了防止越界
int visited[25]={0}; //防止重复选数,这是 dfs 枚举排列的要点
int ans[25]; //放置答案
int pc[25];//构造所有i C n-1 int dfs(int i,int num,int v); //写函数原型是(我的)好习惯! int main(void){
scanf("%d%d",&n,&sum);
//下面构造杨辉三角(即组合数表)
pc[0]=pc[n-1]=1; //杨辉三角性质,两边都是1
if (n>1)
for (int i=1;i*2<n;i++)
pc[i]=pc[n-1-i]=(n-i)*pc[i-1]/i; //利用杨辉三角对称性和组合数公式计算
//下面枚举计算
if (dfs(0,0,0)) //0 仅起占位符作用
for (int i=1;i<=n;i++)
printf("%d ",ans[i]); //输出答案
return 0;
} int dfs(int i,int num,int v){
//参数说明:i 表示已经枚举了前 i 个数(数的序号从 1 开始),num 表示第 i 个数是 num,v 表示前 i 个数的“和”为 v
//返回值说明:返回 0 表示不行(不可能),返回 1 表示找到了可行解。利用返回值就可以在找到第一个解后直接返回了
if (v>sum) //“剪枝”,及时排除不可能情况,加速枚举
return 0; //不可能
if (i==n){ //已经枚举了前 n 个(全部),判断一下是否是可行解
if (v==sum){
ans[i]=num; //放置解
return 1;
}
else
return 0;
}
visited[num]=1; //标记一下“第 i 个数的值已经使用过了”
//下面寻找第 i+1 个数
for (int j=1;j<=n;j++){
if (!visited[j] && dfs(i+1,j,v+pc[i]*j)){ //v+pc[i]*j表示前(i+1)个数的“和”
//注意,如果数的序号从 1 开始,那么第 i 个数的系数实际上是 (i-1) C (n-1)
//执行到这里表示已经找到了可行的解
ans[i]=num;
return 1;
}
}
visited[num]=0; //如果没有找到,一定记得复位,为进一步的寻找做准备
return 0; //执行到这里一定是没有找到解
}
P1118 [USACO06FEB]Backward Digit Sums G/S的更多相关文章
- BZOJ1653: [Usaco2006 Feb]Backward Digit Sums
1653: [Usaco2006 Feb]Backward Digit Sums Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 207 Solved: ...
- Backward Digit Sums(POJ 3187)
Backward Digit Sums Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 5495 Accepted: 31 ...
- Backward Digit Sums(暴力)
Backward Digit Sums Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 5664 Accepted: 32 ...
- 1653: [Usaco2006 Feb]Backward Digit Sums
1653: [Usaco2006 Feb]Backward Digit Sums Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 285 Solved: ...
- POJ3187 Backward Digit Sums 【暴搜】
Backward Digit Sums Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4487 Accepted: 25 ...
- POJ 3187 Backward Digit Sums 枚举水~
POJ 3187 Backward Digit Sums http://poj.org/problem?id=3187 题目大意: 给你一个原始的数字序列: 3 1 2 4 他可以相邻 ...
- 【POJ - 3187】Backward Digit Sums(搜索)
-->Backward Digit Sums 直接写中文了 Descriptions: FJ 和 他的奶牛们在玩一个心理游戏.他们以某种方式写下1至N的数字(1<=N<=10). 然 ...
- Luogu P1118 [USACO06FEB]数字三角形 Backward Digit Sums | 搜索、数学
题目链接 思路:设一开始的n个数为a1.a2.a3...an,一步一步合并就可以用a1..an表示出最后剩下来的数,不难发现其中a1..an的系数恰好就是第n层杨辉三角中的数.所以我们可以先处理出第n ...
- (DFS、全排列)POJ-3187 Backward Digit Sums
题目地址 简要题意: 输入两个数n和m,分别表示给你1--n这些整数,将他们按一定顺序摆成一行,按照杨辉三角的计算方式进行求和,求使他们求到最后时结果等于m的排列中字典序最小的一种. 思路分析: 不难 ...
随机推荐
- Rancher v1.6.29 Docker单节点部署
前言: Docker镜像中心,有两个版本的rancher(1.X),镜像名称为:rancher/server,而rancher(2.X)的镜像名称是rancher/rancher 去daocloud官 ...
- Servlet基本知识
Servlet基本知识 1.IDEA创建第一个Servlet程序xing 这里说明如何使用 IDEA Ultimate 2020.1.3版本来新建第一个web程序.参考 MoonChasing 1.1 ...
- MySQL基本概念及增删改查操作
SQL.DB.DBMS关系 DB: DataBase(数据库,数据库实际上在硬盘上以文件的形式存在) DBMS: DataBase Management System(数据库管理系统,常见的有:MyS ...
- C++ leetcode接雨水
双指针算法"接雨水" 链接:https://leetcode-cn.com/problems/trapping-rain-water/ 给定 n 个非负整数表示每个宽度为 1 的柱 ...
- redis知识点及常见面试题
redis知识点及常见面试题 参考: https://zm8.sm-tc.cn/?src=l4uLj4zF0NCIiIjRnJGdk5CYjNGckJLQrIqNiZaJnpOWjIvQno2Llpy ...
- 华为oj-判断输入的字符串是不是一个有效的IP地址
题目标题: 判断输入的字符串是不是一个有效的IP地址 详细描述: 请实现如下接口 boolisIPAddressValid(constchar* pszIPAddr) 输入:pszIPAddr 字符串 ...
- JDK 5.0新特性
时间:2016-11-5 12:03 JDK5.0新特性 泛型.枚举.静态导入.自动拆装箱.增强for循环.可变参数1.Junit单元测试 测试的对象是类中的一个方法. junit不 ...
- promise小案例
页面中有个板块,需要多张图片加载完之后才能进行显示 //页面中有个板块 需要多张图片加载完之后才能进行显示 const loadImg = (src) => { return new Promi ...
- promise链式调用的应用
then在链式调用时,会等前一个then或者函数执行完毕,返回状态,才会执行回调函数. (1)代码顺序执行,第一步调用了函数cook ,cook执行返回了一个promise,promise返回的是成功 ...
- python--接口自动化经常用到的pytest框架
pytest常用的方法和原理 1.pytest的原理 pytest插件基于pluggy模块:pluggy有三个重要概念:HookspecMarker(用来定义hook函数),HookimplMarke ...