【洛谷2217】[HAOI2007] 分割矩阵(DP水题)

点此看题面

  • 给定一个(a imes b)的矩阵,要求你对它进行(n-1)次划分,每次把一个矩阵按某一行或某一列分成两个。
  • 求这(n)个矩阵各自元素和的最小均方差。
  • (a,b,nle10)

(DP)大水题

首先考虑均方差为:

[sqrt{frac{sum_{i=1}^n(S_i-ar{S})^2}n} ]

显然,(ar{S}=frac {sum s_{i,j}}{n})是一个定值,不妨设(sum s_{i,j}=tot),得到:

[sqrt{frac{sum_{i=1}^n(S_i-frac{tot}n)^2}n}=sqrt{frac{sum_{i=1}^n(nS_i-tot)^2}{n^3}} ]

也就是说我们只需要最小化(sum_{i=1}^n(nS_i-tot)^2)即可。

我们设(f_{x1,y1,x2,y2,k})表示把左上角为((x1,y1)),右下角为((x2,y2))的矩阵划分(k)次,所得的(sum(nS_i-tot)^2)的最小值。

转移过程就是枚举按哪一行/哪一列划分,同时枚举如何把剩下(k-1)次划分分给这两部分。

这种数据范围随便跑。。。

代码:(O(n^7))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 10
#define LL long long
using namespace std;
int a,b,n,tot,s[N+5][N+5];LL f[N+5][N+5][N+5][N+5][N+5];
I LL DP(CI x1,CI y1,CI x2,CI y2,CI k)//DP,写成记忆化搜索的形式
{
	if(~f[x1][y1][x2][y2][k]) return f[x1][y1][x2][y2][k];RI i,j;LL t=1e18;//记忆化
	if(!k) {for(t=0,i=x1;i<=x2;++i) for(j=y1;j<=y2;++j) t+=s[i][j];t=1LL*(n*t-tot)*(n*t-tot);goto End;}//k=0
	for(i=x1;i^x2;++i) for(j=0;j^k;++j) t=min(t,DP(x1,y1,i,y2,j)+DP(i+1,y1,x2,y2,k-1-j));//按某一行分
	for(i=y1;i^y2;++i) for(j=0;j^k;++j) t=min(t,DP(x1,y1,x2,i,j)+DP(x1,i+1,x2,y2,k-1-j));//按某一列分
	End:return f[x1][y1][x2][y2][k]=t;//记忆化
}
int main()
{
	RI i,j;for(scanf("%d%d%d",&a,&b,&n),i=1;i<=a;++i) for(j=1;j<=b;++j) scanf("%d",s[i]+j),tot+=s[i][j];//统计序列总和
	return memset(f,-1,sizeof(f)),printf("%.2lf
",sqrt(1.0*DP(1,1,a,b,n-1)/n/n/n)),0;//注意计算最终答案
}
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu2217.html