USACO:子集(低效)

USACO: Subsets (Inefficient)

本文关键字:低效 子集 USACO      更新时间:2023-10-16

我正在尝试解决来自USACO训练网关的子集。。。

问题陈述

对于从1到N(1<=N<=39)的许多连续整数集,可以将该集划分为两个和相同的集。

例如,如果N=3,可以用一种方式对集合{1,2,3}进行划分,使两个子集的和相同:

{3} 和{1,2}这算作单个分区(即,将顺序计数反转为相同的分区,因此不会增加分区的计数)。

如果N=7,有四种方法可以对集合{1,2,3,…7}进行分区,使得每个分区都有相同的和:

{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,您的程序应该打印包含从1到N的整数的集合可以划分为两个总和相同的集合的方式。如果没有这种方法,请打印0。

你的程序必须计算答案,而不是从表中查找。

结束

在我运行O(N*2^N)之前,我只是简单地排列集合并找到和。

发现这是多么低效,我开始映射和序列。。。http://en.wikipedia.org/wiki/Composition_(数字理论)

在经历了许多编码问题后,我刮出了重复,仍然太慢,所以我回到了原点:(.

现在我更仔细地研究这个问题,看起来我应该试着找到一种方法,不求和,而是通过某种公式直接求和的数量。

如果有人能给我指点如何解决这个问题,我会洗耳恭听的。我用java、C++和python编程。

实际上,有一个更好更简单的解决方案。您应该使用动态编程相反在您的代码中,您将有一个整数数组(其大小为和),其中索引i处的每个值表示可能对这些数字进行分区的方法的数量,以便其中一个分区的和为i。以下是您的代码在C++中的样子:

int values[N];
int dp[sum+1]; //sum is the sum of the consecutive integers
int solve(){
    if(sum%2==1)
        return 0;
    dp[0]=1;
    for(int i=0; i<N; i++){
        int val = values[i]; //values contains the consecutive integers
        for(int j=sum-val; j>=0; j--){
            dp[j+val]+=dp[j];
        }
    }
    return dp[sum/2]/2;
}

这给了你一个O(N^3)的解决方案,它对这个问题来说已经足够快了。

我还没有测试过这段代码,所以可能有语法错误或其他什么,但你明白了。如果你还有什么问题,请告诉我。

这与在多项式(x^1+1/x)(x^2+1/x^2)中查找系数x^0项是一样的。。。(x^n+1/x^n),应该取O(n^3)的一个上界。