[LuoGu P1880 ] 石子合并
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[LuoGu P1880 ] 石子合并相关的知识,希望对你有一定的参考价值。
题目大意:
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
输入输出格式:
输入格式:
数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.
输出格式:
输出共2行,第1行为最小得分,第2行为最大得分.
由于本人是大蒟蒻,所以这道题做了好几个月(其实第一眼看就想到断环成链,但是蒟蒻是完美主义者,所以铁了心要写DP)
断环成链的就不说了,点开LuoGu 题解一大堆.
这里说一下我的DP思路:
若果是一条链,那么这个问题是很好处理的,有状态转移方程(以最小值为例) : f[i][j]=min{ f[i][k]+f[k+1][j]+sum(i,j) } | i<=k<=j.
那么成环之后也可以用类似的状态: 假设石子的序号逆时针递增,则f[i][j] 表示以逆时针方向的最优合并,那么f[i][j]|0<=i<=n-1,0<=j<=n-1 就足以表示所有的情况(lrj:想一想,为什么 =‘-‘) )
蒟蒻觉得用记忆化搜索比用递推好(其实是因为递推的话蒟蒻不知道顺序),那么,请看代码:
1 //Copyright(C)Sunshine. 2 //2017.11.06 3 #include<cstdio> 4 #include<cstring> 5 const int N=100+1,INF=2e9+1; 6 int a[N],sum[N],MinS[N][N],MaxS[N][N],n; 7 bool calMin[N][N],calMax[N][N]; 8 int min(int a,int b){return a<b?a:b;} 9 int max(int a,int b){return a>b?a:b;} 10 inline int SUM(int,int); 11 inline int DP(int,int,int val[N][N],bool vis[][N],int(*)(int,int)); 12 inline void init(); 13 inline void dp(); 14 inline void PrintAnswer(); 15 int main() 16 { 17 init(); 18 dp(); 19 PrintAnswer(); 20 return 0; 21 } 22 inline int SUM(int l,int r) 23 { 24 if(l==r)return a[l]; 25 if(l<r)return ( sum[r]-sum[l]+a[l] ); 26 return (sum[n-1]-sum[l]+a[l])+sum[r]; 27 } 28 inline void init() 29 { 30 memset(MinS,0x7f,sizeof(MinS)); 31 scanf("%d",&n); 32 for(int i=0;i<n;i++) 33 { 34 scanf("%d",&a[i]); 35 sum[i]=sum[i-1]+a[i]; 36 } 37 } 38 inline void dp() 39 { 40 for(int i=0;i<=n-1;i++) 41 for(int j=0;j<=n-1;j++) 42 { 43 if(!calMin[i][j])MinS[i][j]=DP(i,j,MinS,calMin,min); 44 if(!calMax[i][j])MaxS[i][j]=DP(i,j,MaxS,calMax,max); 45 } 46 } 47 inline int DP(int from,int to,int val[][N],bool vis[][N],int (*f)(int,int)) 48 { 49 if(vis[from][to])return val[from][to]; 50 vis[from][to]=true; 51 int ans=(-1)*f(INF,-INF); 52 if(from<to) 53 { 54 if(from==to-1)return val[from][to]=SUM(from,to); 55 for(int k=from;k<to;k++) 56 { 57 int m1=DP(from,k,val,vis,f),m2=DP((k+1)%n,to,val,vis,f); 58 ans=f(ans,m1+m2+SUM(from,to) ); 59 } 60 return val[from][to]=ans; 61 } 62 else if(from==to){return val[from][to]=0;} 63 else 64 { 65 if((from+1)%n==to)return val[from][to]=SUM(from,to); 66 for(int k=(from)%n;k!=to;k=(k+1)%n) 67 { 68 int m1=DP(from,k,val,vis,f),m2=DP((k+1)%n,to,val,vis,f); 69 ans=f(ans,m1+m2+SUM(from,to)); 70 } 71 return val[from][to]=ans; 72 } 73 } 74 inline void PrintAnswer() 75 { 76 int MinA=1e8+1,MaxA=-1,l[2],r[2]; 77 for(int i=0;i<n;i++) 78 { 79 MinA=min(MinA,MinS[i][(i+n-1)%n]); 80 MaxA=max(MaxA,MaxS[i][(i+n-1)%n]); 81 } 82 printf("%d\n%d",MinA,MaxA); 83 }
以上是关于[LuoGu P1880 ] 石子合并的主要内容,如果未能解决你的问题,请参考以下文章