[洛谷P1880]石子合并

    xiaoxiao2025-03-29  4

    描述 在一个园形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。 试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.

    输入格式: 数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数. 输出格式: 输出共2行,第1行为最小得分,第2行为最大得分.

    输入样例: 4 4 5 9 4 输出样例: 43 54

    题解:很经典的问题了,然而我还是只会记忆化搜索。。。 记得要有前缀和优化。

    #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #define LiangJiaJun main #define INF 1999122700 using namespace std; int s[1004],a[1004],n,f[1004][1004]; int ld; int dp1(int i,int j){ if(i == j)f[i][j]=0; if(f[i][j]<INF) return f[i][j]; for(int k=i;k<j;k++) f[i][j]=min(f[i][j],dp1(i,k)+dp1(k+1,j)); return f[i][j]+=s[j]-s[i-1]; } int dp2(int i,int j){ if(i == j)f[i][j]=0; if(f[i][j]>=0) return f[i][j]; for(int k=i;k<j;k++) f[i][j]=max(f[i][j],dp2(i,k)+dp2(k+1,j)); return f[i][j]+=s[j]-s[i-1]; } int LiangJiaJun(){ scanf("%d",&n); ld=(n<<1)-1; for(int i=1;i<=n;i++){ int x; scanf("%d",&x); a[i]=a[i+n]=x; } s[0]=0; for(int i=1;i<=ld;i++)s[i]=s[i-1]+a[i]; int ans = INF; for(int i=1;i<=1000;i++) for(int j=1;j<=1000;j++)f[i][j]=INF; dp1(1,ld); for(int i=1;i<=n;i++) ans = min(ans , f[i][i+n-1]); printf("%d\n",ans); memset(f,-1,sizeof(f)); dp2(1,ld); for(int i=1;i<=n;i++) ans = max(ans , f[i][i+n-1]); printf("%d\n",ans); return 0; }
    转载请注明原文地址: https://ju.6miu.com/read-1297507.html
    最新回复(0)