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的更多相关文章

  1. BZOJ1653: [Usaco2006 Feb]Backward Digit Sums

    1653: [Usaco2006 Feb]Backward Digit Sums Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 207  Solved:  ...

  2. Backward Digit Sums(POJ 3187)

    Backward Digit Sums Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5495   Accepted: 31 ...

  3. Backward Digit Sums(暴力)

    Backward Digit Sums Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 5664   Accepted: 32 ...

  4. 1653: [Usaco2006 Feb]Backward Digit Sums

    1653: [Usaco2006 Feb]Backward Digit Sums Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 285  Solved:  ...

  5. POJ3187 Backward Digit Sums 【暴搜】

    Backward Digit Sums Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 4487   Accepted: 25 ...

  6. POJ 3187 Backward Digit Sums 枚举水~

    POJ 3187  Backward Digit Sums http://poj.org/problem?id=3187 题目大意: 给你一个原始的数字序列: 3   1   2   4  他可以相邻 ...

  7. 【POJ - 3187】Backward Digit Sums(搜索)

    -->Backward Digit Sums 直接写中文了 Descriptions: FJ 和 他的奶牛们在玩一个心理游戏.他们以某种方式写下1至N的数字(1<=N<=10). 然 ...

  8. Luogu P1118 [USACO06FEB]数字三角形 Backward Digit Sums | 搜索、数学

    题目链接 思路:设一开始的n个数为a1.a2.a3...an,一步一步合并就可以用a1..an表示出最后剩下来的数,不难发现其中a1..an的系数恰好就是第n层杨辉三角中的数.所以我们可以先处理出第n ...

  9. (DFS、全排列)POJ-3187 Backward Digit Sums

    题目地址 简要题意: 输入两个数n和m,分别表示给你1--n这些整数,将他们按一定顺序摆成一行,按照杨辉三角的计算方式进行求和,求使他们求到最后时结果等于m的排列中字典序最小的一种. 思路分析: 不难 ...

随机推荐

  1. 机器学习:单元线性回归(python简单实现)

    文章简介 使用python简单实现机器学习中单元线性回归算法. 算法目的 该算法核心目的是为了求出假设函数h中多个theta的值,使得代入数据集合中的每个x,求得的h(x)与每个数据集合中的y的差值的 ...

  2. centos7 更新源

    centos7 yum源更新   先进入到yum源文件cd /etc/yum.repo.d/  1.创建一个repo_bak目录,用于保存系统中原来yum的repo文件. sudo mkdir rep ...

  3. SQL 练习4

    查询不存在" 01 "课程但存在" 02 "课程的情况 SELECT * from sc WHERE cid = '02' AND sid not in (SE ...

  4. mysql事务的4大特性

    事务的四大特性(简称ACID) 1.原子性(Atomicity) 事务是数据库的逻辑工作单位,事务中包括的诸操作要么全做,要么全不做. 2.一致性(Consistency) 事务执行的结果必须是使数据 ...

  5. The requested PHP extension ext-http * is missing from your system. Install or enable PHP's http ex

    composer.json 包含 "require": { "ext-http": "*" } 删掉  "ext-http&quo ...

  6. mysql悲观锁和乐观锁

    悲观锁 查出来的数据必须是根据索引查出来的,不然锁表. # 语法 select * from table where id = 1 for update; 乐观锁 使用一个标识 cas 比较后替换 如 ...

  7. STM32+Air202+Air530+HXDZ-30102-ACC心率血氧GPS采集上传到阿里云

    所有资料都在QQ群1121445919 主要功能 HXDZ-30102-ACC采集心率血氧数据 STM32通过串口将数据转发到air202模块 air202将数据上传到阿里云平台进行展示与处理 整合合 ...

  8. itoa函数递归实现

    库函数中有atoi函数,用意是将字符形式输入的数据转换成数字,而库函数有没有提供一个将数字转换成字符的函数呢?答案是有的,而且功能很是强大,那就是sprintf().snprintf()格式化转换函数 ...

  9. eclipse性能调优的一次记录

    最近因为学习原因,eclipse中插件越来越多,造成eclipse一次次假死,着实很影响工作效率和心情,有时正是兴起,但是造成短片很令人生气,如果eclipse卡顿或者假死,在电脑配置较不错的情况下, ...

  10. Go语言 判断key是否在map里 if _, ok := map[key]; ok

    if val, ok := map[key]; ok { //do something here } 如果key在map里 val 被赋值map[key] ok 是true 否则val得到相应类型的零 ...