• luogu P1880 [NOI1995]石子合并


    题目描述

    题目链接

    思路

    这是一道区间 (DP) 的经典问题,很早就想做这道题目,可是一直没有做。

    考虑最后合并为一堆石子肯定是由两堆石子合并起来得到的,然而这两堆石子也是由上面的情况得到的。所以这个问题就转化为了一个无限递归的子问题。

    我们设 (f[i][j]) 为合并 ([i,j]) 这些石子所花费的最小代价,所以转移就有

    [f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[i][j]) kin[l,r) ]

    其中 (sum[i][j])([i,j]) 区间内所有石子的总花费,因为你不论怎样合并,这次合并的都要加这些代价。需要注意的是 (k<r) 因为如果 (k=r) 那么 (k+1>r) 就不符合条件的区间了。

    然后我们就愉快地解决了这道题目。

    等等,这道题目是在环上,我们可以断环为链,其实就是在将数组复制一遍,这样可以证明可以包含环上的所有情况,其实这样就将问题转化为了在 (2n) 合并相邻的 (n) 个石子的最小代价。

    Code

    #include<bits/stdc++.h>
    using std::min;
    using std::max;
    const int N=2e2+10,INF=1e7+100;
    int n;
    int a[N];
    int f[N][N],ff[N][N],sum[N][N];
    int main()
    {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++)
    	{
    		scanf("%d",a+i);
    		a[i+n]=a[i];
    	}
    	for (int i=1;i<=n*2;i++)
    	{
    		int now=0;
    		for (int j=i;j<=n*2;j++)
    		{
    			now+=a[j];
    			sum[i][j]=now;
    		}
    	}
    	for (int i=1;i<=n*2;i++)
    	{
    		for (int j=1;j<=n*2;j++)
    		f[i][j]=INF;
    	}
    	for (int i=1;i<=n*2;i++)
    	f[i][i]=0;
    	for (int len=2;len<=n;len++)
    	{
    		for (int l=1;l<=n*2;l++)
    		{
    			int r=l+len-1;
    			if (r>n*2) break;
    			for (int k=l;k<=r-1;k++)
    			{
    				f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+sum[l][r]);
    				ff[l][r]=max(ff[l][r],ff[l][k]+ff[k+1][r]+sum[l][r]);
    			}
    		}
    	}
    	int minn=INF,maxx=0;
    	for (int i=1;i<=n*2;i++)
    	{
    		if (i+n-1>n*2) break;
    		minn=min(minn,f[i][i+n-1]);
    		maxx=max(maxx,ff[i][i+n-1]);
    	}
    	printf("%d
    %d
    ",minn,maxx);
    	return 0;
    }
    
  • 相关阅读:
    Array中数据强制数据类型转换
    去除socket编程当中接收到的多余符\0
    <转>在 ASP.NET 中执行 URL 重写
    小牛生产小牛的问题解决集粹
    SAP ABAP鸟瞰【AV+PPT】
    cx_Oracle说:Python访问Oracle并不难
    resolve.conf引起登录HPUX的CDE故障
    HPUX 11i v2安装使用python 2.5.2
    HPUX下使用python发送邮件
    HPUX 11i v2上Oracle10.2基本安装指南
  • 原文地址:https://www.cnblogs.com/last-diary/p/11550421.html
Copyright © 2020-2023  润新知