fzoj 1319 Blocks of Stones(DP:水题)

来源:互联网 发布:网络推广广告 编辑:程序博客网 时间:2024/06/16 13:06

Accept: 183    Submit: 732
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

There are n blocks of stones in a line laying on the ground. Now you are to merge these blocks of stones together with the restriction that you can only merge the neighbouring blocks each time. The score you get for each merging is the number of stones the new blocks has.

Before merging, you are allowed to swap a neighbouring block. You are to calculate the minimal score you will get during the merging process, and the swap position.

 Input

There are multiple test cases. For each case, the first line contains a integer n(n<=100), representing the number of blocks. The second line contains n integers, representing number of stones in each blocks

 Output

For each case, output 2 lines. The first line contains a single integer, representing the minimal score. The second line contains to integers in the form "(k,k+1)", representing the swap position. If there is more than one swap position which can be the minimal score, output the one with the largest k. You should note that : If swap is not needed output "(0,1)".

 Sample Input

32 5 13 1 2 5

 Sample Output

11(2,3)11(0,1)

 Source

chenyan




几个月没写DP,真的是废了。。。

这个题很蛋疼的一点就是还存在交换相邻位置的情况

令s[i]保存1-i项石子总数,则交换a[i],a[i+1]即为s[i] = s[i]-a[i]+a[i+1];

枚举n次交换即可,还要注意在一次交换后要恢复原来的情况

状态转移方程为:

dp[i][j] = min(dp[i][k]+dp[k+1,j], dp[i][j])+s[j]-s[i-1];

这个题先写的记忆化搜索,总是超时(后来才知道写的是纯搜索,没有记忆化尴尬

后来又写DP,真是蛋碎了一地!

代码如下:

#include <stdio.h>#include <string.h>#define MAXN 110#define INF 0x7fffffffint a[MAXN], s[MAXN], dp[MAXN][MAXN];int main(void) {    int tmp, ans, res, x, n, i, j, k, r, t;    while(scanf("%d", &n) != EOF) {        s[0] = 0;        memset(a, 0, sizeof(a));                for(i=1; i<=n; ++i) {            scanf("%d", &a[i]);            dp[i][i] = 0;            s[i] = s[i-1]+a[i];        }        ans = INF;        //dp[i][j] = min(dp[i][k]+dp[k+1,j], dp[i][j])+s[j]-s[i-1];        for(t=0; t<n; ++t) {            if(t>0)  s[t] = s[t]-a[t]+a[t+1];        for(r=1; r<n; ++r) {            //printf("s[%d] = %d\n", r, s[r]);            for(i=1; i<=n-r; ++i) {                j = i+r;                dp[i][j] = INF;                for(k=i; k<j; ++k) {                    tmp = dp[i][k]+dp[k+1][j];                    dp[i][j] = dp[i][j]>tmp ? tmp : dp[i][j];                }                dp[i][j] += s[j]-s[i-1];            }        }        //printf("dp[1][%d] = %d\n", n, dp[1][n]);        tmp = dp[1][n];        if(tmp <= ans) {            ans = tmp;            x = t;        }        if(t>0) s[t]=s[t]-a[t+1]+a[t];//恢复变化前的状态,t==0时为最初不交换的状态        else res = dp[1][n];                }        if(ans == res) x = 0;//如果和最初的结果一样还要令x=0        printf("%d\n", ans);        printf("(%d,%d)\n", x, x+1);            }}

我把搜索改进为记忆化搜索代码的如下:

#include <stdio.h>#include <string.h>#define MAXN 110#define INF 0x7fffffffint a[MAXN], s[MAXN], dp[MAXN][MAXN];int search(int i, int j) {    int ans, tmp, k;    if(dp[i][j] != -1) return dp[i][j];    ans = INF;    for(k=i; k<j; ++k) {        tmp = search(i, k)+search(k+1, j);        ans = ans > tmp ? tmp : ans;    }    return dp[i][j] = ans + s[j]-s[i-1];}int main(void) {    int tmp, ans, res, x, n, i;    while(scanf("%d", &n) != EOF) {        s[0] = 0;        memset(dp, -1, sizeof(dp));        memset(a, 0, sizeof(a));                for(i=1; i<=n; ++i) {            scanf("%d", &a[i]);            s[i] = s[i-1]+a[i];            dp[i][i] = 0;        }        x = 0;        search(1, n);        ans = res = dp[1][n];        for(i=1; i<n; ++i) {            s[i] = s[i]-a[i]+a[i+1];            search(1, n);            if(ans >= dp[1][n]) {                ans = dp[1][n];                x = i;            }            s[i] = s[i]-a[i+1]+a[i];            memset(dp, -1, sizeof(dp));            for(int j=1; j<=n; ++j)                dp[j][j] = 0;        }                if(res == ans)            x = 0;        printf("%d\n", ans);        printf("(%d,%d)\n", x, x+1);            }}


0 0