石子合并题解

题目描述

在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

输入输出格式

输入格式:

数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.

输出格式:

输出共2行,第1行为最小得分,第2行为最大得分.

输入输出样例

输入样例#1: 复制
4
4 5 9 4
输出样例#1: 复制
43
54
题解
对于这个题目,首先想到的是贪心,将和最小的合并到一起,但这种方法肯定是错误的,至于为什么(不会告诉你们我不知道)。
正题来了-对于这个题目,因为石子是一个环,所以一个常规的操作就是拆环成链,至于操作在代码里面有解释。
很容易想到动态转移方程(先是最小的)
f(i,j)=min{f(i,k1),f(k,j)}+w(i,j)(ikj)。
f[i][j]代表从i合到j的最小代价,w[i][j]代表从i到j的重量总和。
我们类比到最大的
g(i,j)=max{g(i,k1),g(k,j)}+w(i,j)(ikj)。
贴上我比较丑陋的代码
 1 #include<bits/stdc++.h>
 2  
 3 using namespace std;
 4 
 5 inline int read(){
 6     int w=1,s=0;
 7     char ch=getchar();
 8     while(ch<'0'||ch>'9') {if (ch=='-') w=-1; ch=getchar();}
 9     while(ch>='0'&&ch<='9') {s=s*10+ch-'0'; ch=getchar();}
10     return s*w;
11 }
12 
13 int a[10000],f[1100][1100],dp[1100][1100],sum[10000],maxx=0,minn=9446413135;
14 
15 int main(){
16     int n=read();
17     for(int i=1;i<=n;i++) a[i]=read(),a[i+n]=a[i];//这里便是拆环成链。
18     for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i];//记录前缀
19     for(int i=2*n-1;i>=1;i--)
20     for(int j=i+1;j<n+i;j++){
21        f[i][j]=0x3f3f3f3f; 
22        for(int k=i;k<j;k++)
23        {
24              f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]); //动态转移方程  
25              dp[i][j]=max(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
26     }
27     }
28     for(int i=1;i<=n;i++){
29         minn=min(minn,f[i][i+n-1]);  //因为是拆环成链,从i带i+n-1这个长度为n的序列便是原来的环从i这个点拆出来的
30         maxx=max(maxx,dp[i][i+n-1]);
31     }
32     cout<<minn<<endl<<maxx;
33     return 0;
34 }
 
    
   


猜你喜欢

转载自www.cnblogs.com/Yldar/p/9700018.html
今日推荐