做题笔记——“动态规划”:子集的和

           经过了许久的学习,就应该将所学沉淀下来。

        那么今天小编记录的,是一道挺有趣的编程题——子集的和。

这道题可以用动态规划(DP)来解决。这次我做的是新学的动态规划类型的题:子集的和……

题目描述

对于从1到N (1 <= N <= 39) 的连续整数集合,能划分成两个子集合,且保证每个集合的数字之和是相等的。

举个例子,如果N=3,对于{1,2,3}能划分成两个子集合,他们每个的所有数字和是相等的:
{3} and {1,2}
这是唯一一种分法(交换集合位置被认为是同一种划分方案,因此不会增加划分方案总数)

如果N=7,有四种方法能划分集合{1,2,3,4,5,6,7},每一种分发的子集合各数字和是相等的:
{1,6,7} 和 {2,3,4,5}     1+6+7=2+3+4+5
{2,5,7} 和 {1,3,4,6}
{3,4,7} 和 {1,2,5,6}
{1,2,4,7} 和 {3,5,6}

给出N,你的程序应该输出划分方案总数,如果不存在这样的划分方案,则输出0。

输入

第1行:一个整数N

输出

第1行:输出划分方案总数,如果不存在则输出0。


样例输入

7

样例输出

4

我们拿到这道题,首先应该判断它应该用哪种算法(思想)来做。

因为这道题的方案数量只与局部最优有关,而且可以划分阶段,所以我选择通过动态规划做。

那么怎么利用动态规划呢?

动态规划的本质其实就是记忆化搜索,但动归是以递推的形式呈现的,动归有以下一些步骤。

1.利用数组表示状态

2.赋初值

3写出动态转移方程式

4利用求解

该题就是一个例子了!

#include<cstdio>
#include<algorithm>
using namespace std;
int n,f[40][808],sum;//利用f数组储存状态f[i][j]代表着用前i个整数中加和为j的方案数
int main()
{
	
 	scanf("%d",&n);
	for(int i=1;i<=n;i++)
 	{f[i][0]=1;sum+=i;}  //如果前i个整数中加和为0,只有1个方案,用sum存总和
	if(sum&1)            //其实就是sum%2==1
	{
                printf("0");
                return 0;   //当总和都是奇数时,是不能分成相等的两个整数的
        }
	for(int i=1;i<=n;i++)   //通过i,j的范围,找f[i][j]
 		for(int j=n*(n+1)/4;j>0;j--)
			if(j>=i)f[i][j]=f[i-1][j]+f[i-1][j-i];   //如果要加第i个数,那么i-1,加和要减去第i个数的值,也就是减去i;如果不加,只用i-1,。两种情况应该相加
			else f[i][j]=f[i-1][j];       //如果j<i,加和就不能减第i个数了,只有1种情况
	 printf("%d",f[n][n*(n+1)/4]);       //前n个整数中加和为n*(n+1)/4的方案数即为解
	return 0;
}

    原文作者:动态规划
    原文地址: https://blog.csdn.net/qq_37630072/article/details/77505210
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞