把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

点此看题面

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

\(DP\)大水题

首先考虑均方差为:

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

显然,\(\bar{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\n",sqrt(1.0*DP(1,1,a,b,n-1)/n/n/n)),0;//注意计算最终答案
}
posted @ 2020-11-03 19:19  TheLostWeak  阅读(90)  评论(0编辑  收藏  举报