code[VS] 1048 石子归并

题目描写叙述 Description

有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子。一次合并的代价为两堆石子的重量和w[i]+w[i+1]。

问安排如何的合并顺序,可以使得总合并代价达到最小。

输入描写叙述 Input Description

第一行一个整数n(n<=100)

第二行n个整数w1,w2...wn  (wi <= 100)

输出描写叙述 Output Description

一个整数表示最小合并代价

例子输入 Sample Input

4

4 1 1 4

例子输出 Sample Output

18

以相邻的石头堆来合并,相当于在一个串中割两半,能够用dp[i][j]表示序号从i到j的石头堆合并的最小cost。

dp[i][j]=dp[i][k]+dp[k+1][j]+sum[i][j](i<k<=j)。当中sum[i][j]代表序号i到j石头堆的重量和。我认为理论上搜索和循环都能做,我用的是搜索,写起来简单无脑。 

#include <bits/stdc++.h>
using namespace std;
int vis[102][102];
int n;
int stone[102];
void init(){
	for(int i=1;i<=102;i++)
	for(int j=1;j<=102;j++)
	vis[i][j]=9999999;
}
int dp(int i,int j){
	if(vis[i][j]<9999999)
	return vis[i][j];
	
	if(j-i==1){
		vis[i][j]=stone[i]+stone[j];
		return vis[i][j];
	}
	if(i==j){
		vis[i][i]=0;
		return 0;
	}
	for(int k=i+1;k<=j;k++){
		int sum=0;
		for(int i1=i;i1<=j;i1++)
		sum+=stone[i1];
		vis[i][j]=min(vis[i][j],dp(i,k-1)+dp(k,j)+sum);
	}
	return vis[i][j];
}

int main(){
	init();
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		scanf("%d",&stone[i]);
	}
	printf("%d\n",dp(1,n));
} 


posted on 2017-04-25 16:47  yjbjingcha  阅读(160)  评论(0编辑  收藏  举报

导航