石子合并类似的问题,要求找出括号的添加方法,最小中间和之和,各个中间和.
设dp[i][j]为i到j之间最小中间和之和
则dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j] + sum[i][j] | i<= k < j) sum[i][j]为i到j的和
base case:dp[i][i] = 0
#include <cstdio> #include <climits> #include <memory.h> using namespace std; const int MAX = 23; int dp[MAX][MAX]; int pos[MAX][MAX]; int val[MAX], sum[MAX][MAX]; void print_path(int i, int j){ if(i == j){ printf("%d", val[i]); return; } printf("("); print_path(i, pos[i][j]); printf("+"); print_path(pos[i][j] + 1, j); printf(")"); } int print_intermedia(int x, int y){ if(x == y)return val[x]; int v = print_intermedia(x, pos[x][y]) + print_intermedia(pos[x][y] + 1, y); printf("%d ", v); return v; } int main(int argc, char const *argv[]){ int N; scanf("%d", &N); for(int i = 1; i <= N; ++i){ scanf("%d", &val[i]); } memset(sum, -1, sizeof(sum)); for(int i = 1; i <= N; ++i){ dp[i][i] = 0; pos[i][i] = i; sum[i][i]= val[i]; for(int j = i + 1; j <= N; ++j){ sum[i][j] = sum[i][j - 1] + val[j]; } } for(int j = 1; j < N; ++j){ for(int i = 1; i + j <= N; ++i){ int opt_v = INT_MAX, opt_p = 0; for(int k = i + j - 1; k >= i; --k){ if(opt_v > dp[i][k] + dp[k + 1][i + j] + sum[i][i + j]){ opt_v = dp[i][k] + dp[k + 1][i + j] + sum[i][i + j]; opt_p = k; } } pos[i][i + j] = opt_p; dp[i][i + j] = opt_v; } } print_path(1, N); printf("\n"); printf("%d\n", dp[1][N]); print_intermedia(1, N); printf("\n"); return 0; }
vijos 1038 添加括号,布布扣,bubuko.com
原文:http://blog.csdn.net/zxjcarrot/article/details/21888315