等和的分割子集

晓萌希望将 11NN 的连续整数组成的集合划分成两个子集合,且保证每个集合的数字和是相等。例如,对于 N=3,对应的集合{1,2,3} 能被划分成{3}{1,2} 两个子集合.

这两个子集合中元素分别的和是相等的。

对于N=3 ,我们只有一种划分方法,而对于 N=7 时,我们将有 4 种划分的方案。

输入格式

输入包括一行,仅一个整数,表示 N(1N39)的值。

输出格式

输出包括一行,仅一个整数,晓萌可以划分对应 N 的集合的方案的个数。当没法划分时,输出 0

样例输入
7
样例输出
4

        最近玩递归玩的有点上瘾,看到这个题,第一想法就是递归,简单粗暴,然后果断TLE。。。无奈之下,试试刚刚get的左神的大套路,居然特么,,,就这样把递归改成动规过了。。。

        递归代码如下:

void fun(int i,int sum){
  if(sum==aim/2){
    cnt++;
    return;
  }
  if(sum>aim/2) return ;
  for(int j = i+1;j < n;j++){
      fun(j,sum+j);
  }
}

       1,考虑动规维度: 由于变量是两个,那么动规的表当然就是二维的啦。

       2,动规初始值:动规的初始值就是递归的出口,对于本题就是dp[i][aim/2]=1;

       3,解得位置:递归第一次传的值是啥,解的位置就是啥啦,递归用的fun(0,0),解就是dp[0][0]了,最后注意本题重复计算了,需要除以2.

       4,转移方程:动规的核心,这特么的会了,code就轻松加愉快了。动规的转移方程就是递归的递归体,不过需要稍微修改一下。比如说递归求y需要x,那么动规则是知道x求y,逆向思维一下,转移方程就get了。

    


附上完整代码:

#include<bits/stdc++.h>
using namespace std;
int cnt=0,n,aim=0;
long long dp[40][800]={0};

int main(){
  cin>>n;
  for(int i=1;i<=n;i++){
    aim+=i;
  }
  if(aim%2)cout<<"0"<<endl;
  else{
  	for(int i=1;i<=n;i++){
  		dp[i][aim/2] = 1;	
	}
	for(int i=aim/2;i>=0;i--){
		for(int j=0;j<=n;j++){
			for(int k=j+1;k<=n;k++){
                if(i>=k)
				dp[j][i-k] += dp[k][i];
			}
		}
	}
	cout<<dp[0][0]/2<<endl;
  }
  return 0;
} 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值