vijos 1038 添加括号

来源:互联网 发布:预算软件破解 编辑:程序博客网 时间:2024/06/06 08:28

石子合并类似的问题,要求找出括号的添加方法,最小中间和之和,各个中间和.

设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;}


0 0