题目描述
在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出一个算法,计算出将 N 堆石子合并成 11 堆的最小得分和最大得分。
其实是简单区间dp板子题,但是因为是圆形操场加上数据范围合理所以就把环形数据改成两倍(手动加区间(就是其实也就是把可以选择的区间按照圆形可选种类扩了一下,其余不怎么变的
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define fi first 4 #define se second 5 #define pi acos(-1.0) 6 #define mp make_pair 7 #define pb push_back 8 #define ls rt<<1 9 #define rs rt<<1|1 10 #define inf 0x3f3f3f3f 11 #define pll pair<LL, LL> 12 #define pii pair<int, int> 13 #define mem(a, b) memset(a, b, sizeof(a)) 14 #define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); 15 16 typedef long long ll; 17 const int N = 2e5+5; 18 const int M = 200+5; 19 const int mod = 1e9+7; 20 //head 21 int a[M],sum[M],dps[M][M],dpl[M][M]; 22 int n,anss,ansl,tpn; 23 int main(){ 24 fio 25 cin>>n; tpn = n*2; sum[0] = 0; 26 27 for(int i = 1;i <= n;++i){cin>>a[i];sum[i] = a[i]+sum[i-1]; } 28 for(int i = n+1;i <=tpn;++i){a[i] = a[i-n];sum[i] = a[i]+sum[i-1];} 29 30 for(int len = 2;len<=n;++len){//当前维护区间长度 31 for(int i = 1,j;i+len-1<=tpn;++i){//起始位置 32 j = i+len-1;dps[i][j] = inf;//因为要取最小值所以初始化为最大值 33 for(int k = i;k < j;++k){//枚举间断处 34 dps[i][j] = min(dps[i][k] + dps[k+1][j] + sum[j]-sum[i-1],dps[i][j]); 35 dpl[i][j] = max(dpl[i][k] + dpl[k+1][j] + sum[j]-sum[i-1],dpl[i][j]); 36 } 37 } 38 } 39 anss = dps[1][n];ansl = dpl[1][n]; 40 for(int i = 1;i <= n;++i){ 41 anss = min(dps[i][i+n-1],anss); 42 ansl = max(dpl[i][i+n-1],ansl); 43 } 44 cout<<anss<<endl;cout<<ansl<<endl; 45 return 0; 46 }