【Ybt OJ】[动态规划 第2章] 区间DP [后半章]

57 篇文章 1 订阅
45 篇文章 0 订阅

「 「 动态规划 」 」 2 2 2章 区间 D P DP DP ( ( ( 2 2 2 ) ) )
目录:

C.消除木块
D.棋盘分割

C . C. C. 例题 3 3 3 消除木块

在这里插入图片描述
在这里插入图片描述
洛谷 l i n k link link

分析:

区间 d p dp dp
c o l k col_k colk 表示 k k k区间的颜色 l e n k len_k lenk表示 k k k区间的长度
先预处理这些
f l , r , k f_{l,r,k} fl,r,k表示 消除 [ l , r ] [l,r] [l,r]区间 在 r r r后有 k k k个与 r r r颜色相同方块的最大分数值
首先考虑直接消除 [ l , r ] [l,r] [l,r]区间 那就是 f l , r − 1 , k + f_{l,r-1,k}+ fl,r1,k+当前 r r r的分数

其次就是区间 d p dp dp 区间分别为 f l , i , l e n [ r ] + k , f i + 1 , r − 1 , 0 f_{l,i,len[r]+k},f_{i+1,r-1,0} fl,i,len[r]+k,fi+1,r1,0
但是要颜色相同 这样就可以消除 [ i + 1 , r − 1 ] [i+1,r-1] [i+1,r1] 再计算 [ l , i ] [l,i] [l,i]
l = r l=r l=r 就直接计算当前的分数
记搜实现

CODE:

#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=255;
int T,n,col[N],len[N],f[N][N][N<<1],r;
int dfs(int l,int r,int k)
{
	if(f[l][r][k]) return f[l][r][k];
	if(l==r) return (len[r]+k)*(len[r]+k);
	f[l][r][k]=dfs(l,r-1,0)+(len[r]+k)*(len[r]+k);
	for(int i=l;i<r-1;i++)
		if(col[i]==col[r])
			f[l][r][k]=max(f[l][r][k],dfs(l,i,len[r]+k)+dfs(i+1,r-1,0));
	return f[l][r][k];
} 
int main(){
	scanf("%d",&T);
	int E=T;
	while(T--)
	{
		scanf("%d",&n);
		int ans=0;
		memset(len,0,sizeof(len));
		memset(col,0,sizeof(col));
		memset(f,0,sizeof(f));
		int k=0;r=-1;
		for(int i=1;i<=n;i++)
		{
			int x;
			scanf("%d",&x);
			if(x==r) len[k]++;
			else
			{
				col[++k]=x;
				len[k]++;
			}
			r=x;
		}
		ans=dfs(1,k,0);
		printf("Case %d: %d\n",E-T,ans);
	}
	
	return 0;
}

D . D. D. 例题 4 4 4 棋盘分割

y b t o j ybtoj ybtoj上的题面有问题 先放 l u o g u luogu luogu
在这里插入图片描述
在这里插入图片描述
洛谷 l i n k link link

分析:

∑ i = 1 n ( x i − x ˉ ) n \sqrt{\frac{\sum_{i=1}^n(x_i-\bar{x})}{n}} ni=1n(xixˉ) 最小 那就是 ∑ i = 1 n ( x i − x ˉ ) n \frac{\sum_{i=1}^n(x_i-\bar{x})}{n} ni=1n(xixˉ)最小
把它展开 就是 ∑ i = 1 n ( x i 2 − 2 x i 2 x ˉ + x ˉ 2 ) n = ∑ i = 1 n x i 2 n − x ˉ 2 \frac{\sum_{i=1}^n(x_i^2-2x_i^2\bar{x}+\bar{x}^2)}{n}=\frac{\sum_{i=1}^nx_i^2}{n}-\bar{x}^2 ni=1n(xi22xi2xˉ+xˉ2)=ni=1nxi2xˉ2
x ˉ = ∑ i = 1 8 ∑ j = 1 8 a i , j n \bar{x}=\frac{\sum_{i=1}^8\sum_{j=1}^8a_{i,j}}{n} xˉ=ni=18j=18ai,j
所以 x ˉ 2 \bar{x}^2 xˉ2是定值 那满足 ∑ i = 1 n x i 2 \sum_{i=1}^nx_i^2 i=1nxi2最小就好了

后面的就是 2 2 2维区间 d p dp dp 分别划分 [ x 1 , x 2 ] [x1,x2] [x1,x2] [ y 1 , y 2 ] [y1,y2] [y1,y2]

f x 1 , y 1 , x 2 , y 2 , k f_{x1,y1,x2,y2,k} fx1,y1,x2,y2,k表示左上角为 ( x 1 , y 1 ) (x1,y1) (x1,y1) 右下角为 ( x 2 , y 2 ) (x2,y2) (x2,y2)的矩阵划分成 k k k个子矩阵的最小 σ 2 \sigma^2 σ2
需要 2 2 2维前缀和 s i , j = ∑ k = 1 i ∑ l = 1 j a k , l s_{i,j}=\sum_{k=1}^i\sum_{l=1}^ja_{k,l} si,j=k=1il=1jak,l
每次转移需要计算子矩阵和 令函数 v a l ( x 1 , y 1 , x 2 , y 2 ) val(x1,y1,x2,y2) val(x1,y1,x2,y2)表示左上角 ( x 1 , y 1 ) (x1,y1) (x1,y1) 右下角 ( x 2 , y 2 ) (x2,y2) (x2,y2)的矩阵和

因为 a n s = m i n { ∑ i = 1 n x i 2 n − x ˉ 2 } ans=min\{\frac{\sum_{i=1}^nx_i^2}{n}-\bar{x}^2\} ans=min{ni=1nxi2xˉ2}
做完 m i n { f x 1 , y 1 , x 2 , y 2 , k } min\{f_{x1,y1,x2,y2,k}\} min{fx1,y1,x2,y2,k} a n s ans ans就等于 f 1 , 1 , 8 , 8 , n − x ˉ 2 \sqrt{f_{1,1,8,8,n}-\bar{x}^2} f1,1,8,8,nxˉ2

数据只有 8 × 8 , n < = 15 8\times8,n<=15 8×8,n<=15 就直接 5 5 5循环 d p dp dp

CODE:

#include<cmath>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<iostream>
using namespace std;
typedef long long ll;
const int N=1e1-1;
int n,a[N][N];
double f[N][N][N][N][N<<1];
double val(int x1,int y1,int x2,int y2)
{
	double res=a[x2][y2]-a[x2][y1-1]-a[x1-1][y2]+a[x1-1][y1-1];
	return res*res/n;
}
int main(){
	scanf("%d",&n);
	for(int i=1;i<=8;i++)
		for(int j=1;j<=8;j++)
		{
			scanf("%d",&a[i][j]);
			a[i][j]+=a[i-1][j]+a[i][j-1]-a[i-1][j-1];
		}
	double X=(double)a[8][8]/n;
	for(int k=1;k<=n;k++)
	for(int x1=1;x1<=8;x1++)
	for(int y1=1;y1<=8;y1++)
	for(int x2=1;x2<=8;x2++)
		for(int y2=1;y2<=8;y2++)
		{
			f[x1][y1][x2][y2][k]=1e9;
			if(k==1)
			{
				f[x1][y1][x2][y2][k]=val(x1,y1,x2,y2);
				continue;
			}
			for(int i=x1;i<x2;i++)
			{
				f[x1][y1][x2][y2][k]=min(f[x1][y1][x2][y2][k],f[x1][y1][i][y2][k-1]+val(i+1,y1,x2,y2));
				f[x1][y1][x2][y2][k]=min(f[x1][y1][x2][y2][k],f[i+1][y1][x2][y2][k-1]+val(x1,y1,i,y2));
			}
			for(int i=y1;i<y2;i++)
			{
				f[x1][y1][x2][y2][k]=min(f[x1][y1][x2][y2][k],f[x1][y1][x2][i][k-1]+val(x1,i+1,x2,y2));
				f[x1][y1][x2][y2][k]=min(f[x1][y1][x2][y2][k],f[x1][i+1][x2][y2][k-1]+val(x1,y1,x2,i));
			}
		}	
	printf("%.3lf",sqrt(f[1][1][8][8][n]-X*X));
	
	return 0;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值