sgu 116

本来是一题很简单的背包题, 结果老是RTE, 看了别人的题解, 最后才搞定, dp题吐血啊....

首先,要搞出dp转移方程, 其次,要考虑,对于问题的所有输入, 是否都经过你编写的dp的那部分代码, 这个很关键, 因为你本来的意图是, 用dp来处理程序的输入, 最后输出结果, 如果出现了bug, 使得程序的输入并不经过你的dp代码, 那肯会出错的!

我的做法是, 先将比N小的super-prime找出来, 这里有个陷阱, 当 N = 1, 会导致物品数量为0, 这个时候, 由于我编写的dp里面,计算的状态是:
f[0...N][0...物品数-1]  => 注意: 第一件物品的编号为0
也就是说, 我的dp所计算的所有情况里并不允许 "物品数为0" 这种情况, 一旦物品数为0, 就会跳过这部分的代码
举例子来说就是, 当N=1的时候, 按照我的程序的逻辑, 最后答案应该就是输出 f[N][-1], 下标是-1啊, 所以RTE了

总之, 用dp的时候, 要认真考虑边界条件, 确保问题的解总是能对应于某个你预料中的合法状态, 因为只有合法的状态才是用正确的方法计算出来的, 所以结果才是正确的, 如果问题的解对应的状态不是合法的, 那么肯定就不对了。

调试的时候, 一定不要怕麻烦, 最简单的情况也要试一下, 因为bug的存在位置是超越人类想象的。RTE一般是边界条件没有考虑周全。

#include <cstdio>
#include <vector>
#include <cmath>
#include <cassert>
#include <algorithm>
using namespace std;

vector<int> primeList;
vector<char> isPrime;

const int NOT_A_PRIME = '\0';
const int IS_A_PRIME = '\1';

int selectPrime(int limit) {
    int k;
    int i;

    primeList.resize(0);
    isPrime.resize(limit + 2);
    for (i = 0; i < isPrime.size(); ++i) isPrime[i] = IS_A_PRIME;
    isPrime[0] = NOT_A_PRIME;
    isPrime[1] = NOT_A_PRIME;

    for (i = 2; i <= limit; ++i) {
        if (isPrime[i]) { primeList.push_back(i); }
        for (k = 0; k < primeList.size(); ++k) {
            int cur = primeList[k] * i;
            if (cur > limit) break;
            isPrime[cur] = NOT_A_PRIME;
            if (i % primeList[k] == 0) break;
        }

    }

}

//==============================================================================


template <class VVType, class T>
void make2DVector(VVType &a, int d, int f, const T &initValue) {
    int i, j;
    a.resize(d);
    for (i = 0; i < d; ++i) {
        a[i].resize(f);
        for (j = 0; j < f; ++j) a[i][j] = initValue;
    }
}

//==============================================================================


bool cmpInt(int x, int y) {
    return !(x < y);
}




int N;
vector<int> v;
vector< vector<int> > f;
vector< vector<char> > w;
vector<int> ansList;


void init() {
    int i;
    scanf("%d", &N);

    selectPrime(N + 20);

    v.resize(0);
    for (i = 0; i < primeList.size(); ++i) {
        if (primeList[i] > N) break;
        if (isPrime[i + 1] == IS_A_PRIME) {
            v.push_back( primeList[i] );
        }
    }


    make2DVector(f, N + 1, 2, -1);
    make2DVector(w, N + 1, v.size() + 1, '+');

}



void trackBackAns() {
    ansList.resize(0);
    int n = N;
    int i = v.size() - 1;
    // assert(0 <= v.size() - 1);
    // assert(i == v.size() - 1);
    // assert(0 <= i && i <= v.size() - 1);
    int k;
    // int step = 0;
    while (1) {
        if (n == 0) return;
        if (i == 0) {
            for (k = 0; k < n / v[0]; ++k) ansList.push_back(v[0]);
            return;
        } else if (w[n][i] == '0') {
             i = i - 1;
        } else if (w[n][i] == '1') {
            ansList.push_back(v[i]);
            n = n - v[i];
        } else {
            // assert(0);
        }
    }
}


void dp() {
    int n, i;

    int wh = 0;

    for (i = 0; i < v.size(); ++i) {
        wh = 1 - wh;
        for (n = 0; n <= N; ++n) {
            f[n][wh] = -1;
            if (n == 0) {
                f[n][wh] = 0;
                w[n][i] = '_';
                continue;
            }
            if (i == 0) {
                f[n][wh] = n % v[i] == 0 ? n / v[i] : -1;
                w[n][i] = '*';
                continue;
            }

            if (f[n][1 - wh] != -1) {
                f[n][wh] = f[n][1 - wh];
                w[n][i] = '0';
            }
            if ( (n - v[i] >= 0) && (f[n - v[i]][wh] != -1) && (f[n][wh] == -1 || 1 + f[n-v[i]][wh] < f[n][wh]) ) {
                f[n][wh] = 1 + f[n-v[i]][wh];
                w[n][i] = '1';
            }

        }


    }

    if (f[N][wh] == -1) { printf("0\n"); return; }
    printf("%d\n", f[N][wh]);

    trackBackAns();

    sort(ansList.begin(), ansList.end(), cmpInt);

    for (i = 0; i < ansList.size(); ++i) {
        printf("%d", ansList[i]);
        if (i != ansList.size() - 1) printf(" ");
    }
    printf("\n");
}



int main() {
    init();
    if (v.size() <= 0) { printf("0\n"); return 0; }

    dp();
    return 0;
}


你可能感兴趣的:(sgu 116)