星夜行 2018-05-05
$dp[i][j]$表示前$i$个仓库由前$j$个人来守卫能取得的最大安全值;
$cost[i][j]$表示前$i$个仓库由前$j$个人来守护在能取得的最大安全值的情况下的最小花费。
AC代码
//#define LOCAL
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define INF 0x3f3f3f3f
const int maxn = 100 + 5;
const int maxm = 30 + 5;
int a[maxm];
int dp[maxn][maxm], cost[maxn][maxm];
void solve(int n, int m) {
    // init
    memset(dp, 0, sizeof(dp));
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            // not choose j
            dp[i][j] = dp[i][j-1];
            // choose j
            for(int k = 1; k <= i; k++) {
                int x;
                if(k == i) x = a[j] / k;
                else x = min(a[j] / k, dp[i-k][j-1]);
                if(x > dp[i][j]) {
                    dp[i][j] = x;
                }
            }
        }
    }
    memset(cost, INF, sizeof(cost));
    memset(cost[0], 0, sizeof(cost[0]));
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            cost[i][j] = cost[i][j-1];
            for(int k = 1; k <= i; k++) {
                int safe = a[j] / k;
                if(safe >= dp[n][m]) {
                    cost[i][j] = min(cost[i][j], cost[i-k][j-1] + a[j]);
                }
            }
        }
    }
}
int main() {
#ifdef LOCAL
    freopen("data.in", "r", stdin);
    freopen("data.out", "w", stdout);
#endif
    int n, m;
    while(scanf("%d%d", &n, &m) == 2 && n && m) {
        for(int i = 1; i <= m; i++) {
            scanf("%d", &a[i]);
        }
        solve(n, m);
        printf("%d %d\n", dp[n][m], dp[n][m]==0?0:cost[n][m]);
    }
    return 0;
}如有不当之处欢迎指出!
动态规划有时被称为递归的相反的技术。动态规划方案通常使用一个数组来建立一张表,用于存放被分解成众多子问题的解。当算法执行完毕,最终的解法将会在这个表中找到。今天我们先从我们最熟的斐波那契数列数列开始。
#include <iostream> #include <algorithm> #include <cstring> #include <cstdio&am