1 条题解

  • 0
    @ 2025-5-15 12:02:26

    解题思路

    问题分析:

    这是一个典型的动态规划问题,类似于矩阵链乘法或石子合并问题。由于地块是环形排列的,我们需要将其拆解为线性问题进行处理。通常的方法是复制数组,将环形问题转化为线性问题。每次分割的代价是分割后两部分中较大的面积乘以系数F,目标是找到分割顺序使得总代价最小。

    动态规划状态定义:

    定义dp[i][j]dp[i][j]表示将区间[i,j][i,j]的地块分割成单独地块的最小总代价。初始状态:dp[i][i]=0dp[i][i]=0,因为单个地块无需分割。状态转移:对于区间[i,j][i,j],枚举所有可能的分割点k,将区间分为[i,k][i,k][k+1,j][k+1,j],则分割代价为max(sum(i,k),sum(k+1,j))×Fmax(sum(i,k),sum(k+1,j))×F,总代价为dp[i][k]+dp[k+1][j]+costdp[i][k]+dp[k+1][j]+cost

    环形处理:

    将原数组复制一份接在原数组后面,形成长度为2N2N的数组。对每个可能的起点i1iNi(1≤i≤N),计算dp[i][i+N1]dp[i][i+N-1],取最小值作为答案。

    前缀和优化:

    使用前缀和数组ss快速计算区间和,s[i]s[i]=∑XXk_kkk11ii)。

    解题方法

    输入处理:

    读取NNFF,如果NN=00F=0F=0,则结束程序。读取地块面积数组valval,并将其复制一份接在后面,形成长度为2N2N的数组。

    初始化:

    初始化前缀和数组ss,其中s[i]=s[i1]+val[i]s[i]=s[i-1]+val[i]。初始化动态规划数组dpdp,其中dp[i][i]=0dp[i][i]=0

    动态规划填表:

    按区间长度lenlen从小到大进行遍历,从22NN。对于每个区间[i,j][i,j],枚举所有可能的分割点k,计算分割后的代价,并更新dp[i][j]dp[i][j]

    求解最小值:

    遍历所有可能的起点ii,计算dp[i][i+N1]dp[i][i+N-1],取最小值作为答案。输出最小值乘以FF,保留两位小数

    C++代码实现:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int dp[410][410],val[410],s[410],INF=1e9;
    int main()
    { int n,N,i,j,k,len,ans;
      double p;
      while(~scanf("%d%lf",&n,&p) && n)
      { for(i=1;i<=n;i++)
        { scanf("%d",&val[i]);
          val[i+n]=val[i];
        }
        N=n*2;
        for(i=1;i<=N;i++)
        { dp[i][i]=0;
          s[i]=s[i-1]+val[i];
        }
        for(len=1;len<n;len++)
         for(i=1;i+len<=N;i++)
         { j=i+len;
           dp[i][j]=INF;
           for(k=i;k<j;k++)
            dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+max(s[k]-s[i-1],s[j]-s[k]));
         }
        ans=INF;
        for(i=1;i<=n;i++)
         ans=min(ans,dp[i][i+n-1]);
        printf("%.2f\n",ans*p);
      }
    }
    • 1

    信息

    ID
    1087
    时间
    1000ms
    内存
    256MiB
    难度
    10
    标签
    递交数
    1
    已通过
    1
    上传者