2019.09.14日常总结兼洛谷P1880题解

洛谷 P 1880 P1880 P1880

【题意】: 在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的 2 2 2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出 1 1 1个算法,计算出将 N N N堆石子合并成1堆的最小得分和最大得分.

【思路】: 很经典的区间 d p dp dp的题目,记 f [ i ] [ j ] f[i][j] f[i][j]表示清除 i i i j j j堆石子的最小耗体力,求最大耗体力类似。记 s [ i ] s[i] s[i]表示 a [ 1 ] + a [ 2 ] + a [ 3 ] + . . . + a [ i ] a[1]+a[2]+a[3]+...+a[i] a[1]+a[2]+a[3]+...+a[i],即 s [ i ] = ∑ j = 1 i a [ j ] s[i]=\sum ^i_{j=1} a[j] s[i]=j=1ia[j],所以有 f [ i ] [ j ] = m i n { f [ i ] [ k ] + f [ k + 1 ] [ j ] + s [ j ] − s [ i − 1 ] } f[i][j]=min\{f[i][k]+f[k+1][j]+s[j]-s[i-1]\} f[i][j]=min{f[i][k]+f[k+1][j]+s[j]s[i1]},其中 i ≤ k < j i \leq k < j ik<j。至于环,只需把环拆成长为 2 × n − 1 2 \times n - 1 2×n1的链即可,新链需保证 a [ i ] = a [ i + n ] ( 1 ≤ i ≤ n ) a[i]=a[i+n](1 \leq i \leq n) a[i]=a[i+n](1in)

【代码】:

//By HPXXZYY
#include 
using namespace std;
const int N=210;
int a[N],s[N],k,l,i,n,ans;
int f[N][N],g[N][N],j,tot;
int main(){
//	freopen("t1.in","r",stdin);
	scanf("%d",&n);
	for(i=1;i<=n;i++){
		scanf("%d",&a[i]);
		a[i+n]=a[i];
//		s[i]=s[i-1]+a[i];
	}
//	for(i=1;i<=2*n;i++)
//	printf("a[%d]=%d\n",i,a[i]);
	memset(f,127,sizeof(f));
	for(i=1;i<=2*n;i++)
	s[i]=s[i-1]+a[i];
	for(i=1;i<=2*n;i++)
	f[i][i]=g[i][i]=0;
	for(l=2;l<=n;l++)
	for(j=l;j<=2*n;j++){
		i=j-l+1;
		for(k=i;k<j;k++){
			f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+s[j]-s[i-1]);
			g[i][j]=max(g[i][j],g[i][k]+g[k+1][j]+s[j]-s[i-1]);
		}
	}
	tot=0x3f3f3f3f;
	for(i=1;i<=n;i++){
		ans=max(ans,g[i][i+n-1]);
		tot=min(tot,f[i][i+n-1]);
	}
	cout<<tot<<"\n"<<ans;
	return 0;
}

最后,安利一下我 ( H P X X Z Y Y ) (HPXXZYY) (HPXXZYY)的博客:https://www.luogu.org/blog/hpwwzyy2012/

你可能感兴趣的:(原创)