Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 组合数学-糖果_C++_Algorithm_Dynamic Programming_Combinatorics - Fatal编程技术网

C++ 组合数学-糖果

C++ 组合数学-糖果,c++,algorithm,dynamic-programming,combinatorics,C++,Algorithm,Dynamic Programming,Combinatorics,我在一次比赛中发现了这个问题,至今还没有找到解决办法 这个男孩有苹果,放在盒子里。在一个箱子中,不超过N/2。 他能用多少方法把糖果装进盒子里 所以我要做的是使用DP实现解决方案。这是我的密码: #include <iostream> #include <cmath> #include <cstring> #include <algorithm> #include <unistd.h> #include <vector> #

我在一次比赛中发现了这个问题,至今还没有找到解决办法

这个男孩有苹果,放在盒子里。在一个箱子中,不超过N/2。 他能用多少方法把糖果装进盒子里

所以我要做的是使用DP实现解决方案。这是我的密码:

#include <iostream>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <unistd.h>
#include <vector>
#define size 1002
using namespace std;

long long a[size][size];
int n, k;
int main()
{
    cin >> n >> k;
    int kk = n/2;

    for(int i = 0; i <= k; ++i)
        a[0][i] = 1;
    a[0][0] = 0;

    for(int i = 0; i <= kk; ++i)
        a[i][1] = 1;

    for(int i = 1; i <= n; ++i) {

        for(int j = 2; j <= k; ++j) {
            int index = 0;
            long long res = 0;
            while(1) {
                res += a[i-index][j - 1];
                index += 1;

                if(index == kk + 1 || i-index < 0)
                    break;
            }
            a[i][j] = res;

        }
    }
    cout << a[n][k] << endl;

}
#包括
#包括
#包括
#包括
#包括
#包括
#定义尺寸1002
使用名称空间std;
长a[尺寸][尺寸];
int n,k;
int main()
{
cin>>n>>k;
int kk=n/2;

对于(int i=0;i,通过以下观察,您可以轻松地将时间复杂度从O(kn^2)降低到O(nk):

for(int i = 1; i <= n; ++i) {

    for(int j = 2; j <= k; ++j) {
        int index = 0;
        long long res = 0;
        while(1) {
            res += a[i-index][j - 1];
            index += 1;

            if(index == kk + 1 || i-index < 0)
                break;
        }
        a[i][j] = res;

    }
}
注意:在数组
sum
的初始化步骤中不处理上述代码,也不处理i 更新:

我下面的Java解决方案通过使用类似的想法而被接受:

public static void main(String[] args) throws FileNotFoundException {
    // PrintWriter out = new PrintWriter(new FileOutputStream(new File(
    // "output.txt")));
    PrintWriter out = new PrintWriter(System.out);
    Scanner in = new Scanner();
    int n = in.nextInt();
    int s = in.nextInt();
    BigInteger[][] dp = new BigInteger[n + 1][2];
    BigInteger[][] count = new BigInteger[2][n + 1];
    int cur = 1;
    for (int i = 0; i <= n / 2; i++) {
        dp[i][0] = BigInteger.ONE;
        count[0][i] = (i > 0 ? count[0][i - 1]  : BigInteger.ZERO)
                .add(dp[i][0]);

    }
    for (int i = n / 2 + 1; i <= n; i++) {
        dp[i][0] = BigInteger.ZERO;
        count[0][i] = count[0][i - 1];
    }
    for (int i = 2; i <= s; i++) {
        for (int j = 0; j <= n; j++) {

            dp[j][cur] = dp[j][1 - cur].add((j > 0 ? count[1 - cur][j - 1]
                    : BigInteger.ZERO)
                    .subtract(j > n / 2 ? count[1 - cur][j - (n / 2) - 1]
                            : BigInteger.ZERO));

            count[cur][j] = (j > 0  ? count[cur][j - 1] : BigInteger.ZERO)
                    .add(dp[j][cur]);
        }
        cur = 1 - cur;
    }
    out.println(dp[n][1 - cur]);
    out.close();
}
publicstaticvoidmain(字符串[]args)抛出FileNotFoundException{
//PrintWriter out=新的PrintWriter(新文件输出流)(新文件(
//"output.txt),;
PrintWriter out=新的PrintWriter(System.out);
扫描仪输入=新扫描仪();
int n=in.nextInt();
int s=in.nextInt();
BigInteger[]dp=新的BigInteger[n+1][2];
BigInteger[][]计数=新的BigInteger[2][n+1];
int cur=1;
对于(inti=0;i0?计数[0][i-1]:biginger.ZERO)
。加入(dp[i][0]);
}
对于(inti=n/2+1;i0?计数[cur][j-1]:biginger.ZERO)
.添加(dp[j][cur]);
}
cur=1-cur;
}
out.println(dp[n][1-cur]);
out.close();
}

您的代码是否为较小的输入提供了正确的结果?@tobi303是的,该解决方案对于较小的输入是正确的。请看最后一行给出了一个封闭的公式来计算数字(将(
k
m
R
)分别替换为(
N
S
(N/2)
),我猜是这样的。)“在一个小盒子中放置的糖果不得超过N/2”应为“任何小盒子中的糖果不得超过N/2”“?数字的大小如何?如果我使用BigInteger算法,时间复杂度将再次增加。@James BigInteger可以,因为我们只需要进行加法/减法运算,所以时间复杂度不会显著增加。我已提交并通过实现具有类似想法的Java解决方案而被接受。
public static void main(String[] args) throws FileNotFoundException {
    // PrintWriter out = new PrintWriter(new FileOutputStream(new File(
    // "output.txt")));
    PrintWriter out = new PrintWriter(System.out);
    Scanner in = new Scanner();
    int n = in.nextInt();
    int s = in.nextInt();
    BigInteger[][] dp = new BigInteger[n + 1][2];
    BigInteger[][] count = new BigInteger[2][n + 1];
    int cur = 1;
    for (int i = 0; i <= n / 2; i++) {
        dp[i][0] = BigInteger.ONE;
        count[0][i] = (i > 0 ? count[0][i - 1]  : BigInteger.ZERO)
                .add(dp[i][0]);

    }
    for (int i = n / 2 + 1; i <= n; i++) {
        dp[i][0] = BigInteger.ZERO;
        count[0][i] = count[0][i - 1];
    }
    for (int i = 2; i <= s; i++) {
        for (int j = 0; j <= n; j++) {

            dp[j][cur] = dp[j][1 - cur].add((j > 0 ? count[1 - cur][j - 1]
                    : BigInteger.ZERO)
                    .subtract(j > n / 2 ? count[1 - cur][j - (n / 2) - 1]
                            : BigInteger.ZERO));

            count[cur][j] = (j > 0  ? count[cur][j - 1] : BigInteger.ZERO)
                    .add(dp[j][cur]);
        }
        cur = 1 - cur;
    }
    out.println(dp[n][1 - cur]);
    out.close();
}