如何验证动态编程解决方案对竞争性编程任务的正确性?

时间:2016-05-10 14:37:13

标签: c++ recursion dynamic-programming

我正在尝试开发系统方法来提出动态编程(DP)解决方案 - 按照某些步骤,您可以找到有效的问题解决方案。

理念,基本上是以下内容:从递归开始,调整它以最小化参数数量,这允许您定义问题并添加记忆,之后您可以轻松想出一个DP解决方案。事实证明,事情并非那么简单。

不能简单地将递归解决方案转移到DP中。 例如。查看来自USACO http://train.usaco.org/usacoprob2?a=9OS8tkGfsX5&S=subset

的子集和PS

这是我使用将递归转换为DP的方法的代码。

#include <cstdio>
#include <iostream>
#include <cstdint>
#include <cstring>
using namespace std;
const int MAX_SUBSETSUM = (39+1)*39/4;
const int MAX_N = 39;
int memo[MAX_SUBSETSUM+1][MAX_N+1];
const int NOT_VISITED = -1;
// resembles 0-1 knapsack problem
// we need to select numbers that will go to
// the first set and those sum is totalSum/2
// so we have two sets of equal sum
int recur(int sum, int num) {
  int counter = 0;
  // ### 1.Base case
  if(sum == 0)
    return 1;
  if(sum < 0 || num <= 0)
    return 0;

  // ### Memoization
  if(memo[sum][num] != NOT_VISITED)
    return memo[sum][num];

  // ### 2.Recursive step
  for(int nextNum = 1; nextNum < num; ++nextNum) {
    if(nextNum > sum)
      break;
    //### 3. Make a decision
    const int withNumber = recur(sum - num, nextNum);
    const int withOutNumber = recur(sum, nextNum);
    counter = withNumber + withOutNumber;
  }
  memo[sum][num] = counter;
  return counter;
}


int solveDP(int subsetSum, int N) {
  if(subsetSum & 1)
    return 0;

  int dp[MAX_SUBSETSUM+1][MAX_N+1];
  memset(dp,0,sizeof(dp));
  // fill in base cases
  for(int i = 0; i <= N; ++i) {
    // when subsetsum is 0, we have one way (we pick no nubers)
    dp[0][i] = 1;
  }

  for(int sum =1; sum <=subsetSum; ++sum) {
    for(int num = 1; num <= N; ++num) {
      if(sum >= num)
        dp[sum][num] = dp[sum - num][num-1]/*with num*/ + dp[sum][num-1]/*without*/;
      else 
        dp[sum][num] = dp[sum][num-1]/*without*/;
    }
  }
  return dp[subsetSum][N]/2; // NB!!! /2 - came up with it
}

int main() {
  //freopen("preface.in", "r", stdin);
  //freopen("preface.out", "w", stdout);
  const int N = 7;
  const int subsetSum = (N+1)*N/4;
  memset(memo, NOT_VISITED, sizeof(memo));
  int res = recur(subsetSum, N);
  res = solveDP(subsetSum, N);
  return 0;
}

在DP中你必须得到一半的结果(见return dp[subsetSum][N]/2;)。我发现它是因为我有两个版本,结果不同,所以它涉及像试错法调整DP到递归。 我能够理解为什么只有在用纸和笔在DP桌上玩之后才会发生什么,所以我注意到结果是双重计算的。 这帮助了我。

但是当你在编程比赛中遇到DP问题时该怎么办,你的时间有限,显然不能用DP桌来玩, 你可以建议一些技术,以验证我的DP解决方案的结果,以确保它是正确的。

我的目标是减少错误尝试的时间和次数。

1 个答案:

答案 0 :(得分:-2)

制作一个简单的蛮力程序并运行一个小的测试输入以比较 暴力和您的DP程序导致的结果。 “如有疑问,请使用蛮力”

相关问题