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
Output
Sample Input
Sample Output
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 0x7fffffff
int 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 0x7fffffff
int 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);
}
}