USACO 2.2.2 Subset Sums解题报告
分类:DP,递推,记忆化搜索
作者:ACShiryu
时间:2011-7-15
Subset Sums
JRM
For many sets of consecutive integers from 1 through N (1 <= N <= 39), one can partition the set into two sets whose sums are identical.
For example, if N=3, one can partition the set {1, 2, 3} in one way so that the sums of both subsets are identical:
- {3} and {1,2}
This counts as a single partitioning (i.e., reversing the order counts as the same partitioning and thus does not increase the count of partitions).
If N=7, there are four ways to partition the set {1, 2, 3, ... 7} so that each partition has the same sum:
- {1,6,7} and {2,3,4,5}
- {2,5,7} and {1,3,4,6}
- {3,4,7} and {1,2,5,6}
- {1,2,4,7} and {3,5,6}
Given N, your program should print the number of ways a set containing the integers from 1 through N can be partitioned into two sets whose sums are identical. Print 0 if there are no such ways.
Your program must calculate the answer, not look it up from a table.
PROGRAM NAME: subset
INPUT FORMAT
The input file contains a single line with a single integer representing N, as above.
SAMPLE INPUT (file subset.in)
7
OUTPUT FORMAT
The output file contains a single line with a single integer that tells how many same-sum partitions can be made from the set {1, 2, ..., N}. The output file should contain 0 if there are no ways to make a same-sum partition.
SAMPLE OUTPUT (file subset.out)
4
题目大意就是求讲数据1…N分成两组,使得两组中元素的和加起来相等,求这样分组的情况数
可以利用递推的方法求该题的解,注意:f(k,a)=(f(k-1,a+k)+f(k-1,a-k))/2;其中f(k,a)表示讲1…k元素分两组,使第一组比第二组多a;
因为k只可能分到第一组或第二组这两种情况,如果k加到第一组后使得第一组比第二组多a,则要原来的分组中第一组比第二组多a-k
同理如果k加到第二组后使得第一组比第二组多a,则要原来的分组中第一组比第二组多a+k。
因为交换两组元素后也满足条件,而只算一个解,故后面要除2;
很显然题目要求的是f(N,0);
为节省递推时间,可使用记忆化搜索,考虑到数据不大,又a有正负之分,可加数组适当开大。
数据分析:N最大为39,32位整数可能存不下,故要使用64位扩展,故要将数据声明为long long .因为使用的是记忆化搜索,很大程度上减少了重复搜索的情况,时间复杂度为O(n^3),远优于O(2^n),不会超时.。
参考代码:
1 /* 2 ID:shiryuw1 3 PROG:subset 4 LANG:G++ //64位整数要用long long 5 */ 6 #include<iostream> 7 #include<cstdlib> 8 #include<cstdio> 9 #include<cstring> 10 #include<algorithm> 11 #include<cmath> 12 using namespace std; 13 int sum=0; 14 int n; 15 long long fid[40][2000]; //是否寻找过dp(k,a+1000),当为-1时为否16 long long dp(int k,int a) 17 { 18 if(k==0) 19 { //当为0时不合要求,故返回020 return 0; 21 } 22 if(k==1) 23 { //当为1是可知只有可能两边的集合相差只能为1或-124 if(abs(a)==1) 25 return 1; 当相差为1或-1时,则有一种情况符合26 return 0; 27 } 28 if(k==2) 29 { //理由同k=1时30 if(abs(a)==1||abs(a)==3) 31 return 1; 32 return 0; 33 } 34 if(fid[k][a+1000]==-1) //如果k,a没有访问过,则访问,并将访问结果存在该数组中,很明显该数组的结果不会再是-1否则直接返回fid[k][a+1000],避免重复搜索。35 fid[k][a+1000]=dp(k-1,a+k)+dp(k-1,a-k); 36 return fid[k][a+1000]; 37 }38 39 int main() 40 { 41 freopen("subset.in","r",stdin); 42 freopen("subset.out","w",stdout); 43 cin>>n; 44 memset(fid,-1,sizeof(fid)); //初始化fid数组为-145 printf("%lld\n",dp(n,0)/2); 寻找把1……N分成两组后使两组相差0的情况数46 return 0; 47 }
转载于:https://www.cnblogs.com/ACShiryu/archive/2011/07/15/2107785.html
USACO 2.2.2 Subset Sums解题报告相关推荐
- USACO 3.3.2 Shopping Offers解题报告
写在前面:因为之前没写的C++的USACO Training的解题报告太多--所以就不写了,要是想要代码可以联系我:xiedong_1993@foxmail.com 这题就是传说中的五维背包,其实写起 ...
- USACO Section 1.5 Prime Palindromes 解题报告
题目 题目描述 题目就是给定一个区间[a,b]((5 <= a < b <= 100,000,000)),我们需要找到这个区间内所有既是回文串又是素数的数字. 输入样例 5 500 ...
- usaco 2.1.4 Subset Sums 【母函数】
(1+x)*(1+x^2)*(1+x^3)*--*x^n 则 x^(n*(n+1)/2) 的系数一半为ans /*ID: w.x.f.g1PROG: subsetLANG: C++ */#incl ...
- USACO Section2.1 Hamming Codes 解题报告 【icedream61】
hamming解题报告 ---------------------------------------------------------------------------------------- ...
- USACO Section2.2 Preface Numbering 解题报告 【icedream61】
preface解题报告 ---------------------------------------------------------------------------------------- ...
- usaco ★Subset Sums 集合
★Subset Sums 集合 对于从 1 到 N 的连续整集合合,能划分成两个子集合,且保证每个集合的数字和是相等的. 举个例子,如果 N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数 ...
- USACO Section1.3 Combination Lock 解题报告
combo解题报告 -- icedream61 博客园(转载请注明出处) --------------------------------------------------------------- ...
- USACO Section1.5 Superprime Rib 解题报告
sprime解题报告 -- icedream61 博客园(转载请注明出处) -------------------------------------------------------------- ...
- USACO Training Section 1.3 Calf Flac 解题报告AC代码
解题报告: 主要方法是生长法,考虑每一位的左右各有多长的回文串,输出最长的那个,比较好想--不过要注意区分字串的奇偶. 其他实现细节看代码里的注释吧-- AC代码: /* ID: yuanmz91 P ...
最新文章
- Apache Flink 漫谈系列(12) - Time Interval(Time-windowed) JOIN...
- Unable to get repr for<class‘torch.Tensor‘>
- php的$_SERVER['HOSTNAME']
- 3.2 目标点检测-深度学习第四课《卷积神经网络》-Stanford吴恩达教授
- mysql主从复制思考_Mysql主从复制(拓展博客文章分享及思考)
- 【Linux】Linux中vim的使用
- Ajax — 大事件项目(第二天)
- 【译】XNA Shader 程序设计(二)
- mongodb备份还原
- BZOJ 3282 Link Cut Tree (LCT)
- Python-Pandas
- MATLAB中的线性插值
- html字体加粗代码_9102年了,公众号还不会换字体?
- 28335之GPIO输入
- 深度解读,北斗与综合PNT体系
- 随机无梯度Frank-Wolfe方法的统一分析
- 用KOPPT,大家的姿势对了没?
- 查看Win10激活剩余时间
- CSS第四篇(复合选择器)
- 一件登录facebook_Facebook抵制抵制是防火的,那是一件好事
热门文章
- python全栈脱产第25天------组合、多态、封装、property装饰器
- 微信小程序 --- 图片自适应、本地图片的使用
- 在windows环境下基于sublime text3的node.js开发环境搭建
- 2015-03-06——正则表达式基础
- JAVA GUI关闭按钮不起作用(用SwingWorker解决)
- linux df命令参数详解
- recycleView 滑动删除Item,拖拽切换Item,你想了解的都在这儿
- Observable.OnSubscribe 的理解
- Echarts 动态获取数据进行图表的展示
- NodeJs初学者经典入门解析