【BZOJ 1048】 [HAOI2007]分割矩阵

1048: [HAOI2007]分割矩阵

Time Limit: 10 Sec  Memory Limit: 162 MB

Submit: 498  Solved: 362

[Submit][Status]

Description

将一个a*b的数字矩阵进行如下分割:将原矩阵沿某一条直线分割成两个矩阵,再将生成的两个矩阵继续如此分割(当然也可以只分割其中的一个),这样分割了(n-1)次后,原矩阵被分割成了n个矩阵。(每次分割都只能沿着数字间的缝隙进行)原矩阵中每一位置上有一个分值,一个矩阵的总分为其所含各位置上分值之和。现在需要把矩阵按上述规则分割成n个矩阵,并使各矩阵总分的均方差最小。请编程对给出的矩阵及n,求出均方差的最小值。

Input

第一行为3个整数,表示a,b,n(1

Output

仅一个数,为均方差的最小值(四舍五入精确到小数点后2位)

Sample Input

5 4 4

2 3 4 6

5 7 5 1

10 4 0 5

2 0 2 3

4 1 1 1

Sample Output

0.50

为了方便计算先把求平均方差的公式展开化简,无论怎样分割平均数都不变。

原来的式子就变成了(x1^2+x2^2+...+xn^2)/n-(tot/n)^2

那么就是要让x的平方之和最小。

f[x1][y1][x2][y2][k]表示以(x1,y1)为左上角,(x2,y2)为右下角,把这个矩阵分成k份的最小平方和。

那么我们枚举切割位置(横着、竖着),再枚举切割后的两块中一块分成的块数(1~k-1),用记忆化搜索来做就可以了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int f[15][15][15][15][15],n,pre[15][15],x[15][15],a,b;
bool ok(int x1,int y1,int x2,int y2,int k)
{
	if ((x2-x1+1)*(y2-y1+1)>=k) return true;
	return false;
}
int cal(int x1,int y1,int x2,int y2)
{
	return (pre[x2][y2]-pre[x1-1][y2]-pre[x2][y1-1]+pre[x1-1][y1-1]);
}
int dp(int x1,int y1,int x2,int y2,int k)
{
	if (f[x1][y1][x2][y2][k]!=-1) return f[x1][y1][x2][y2][k];
	if (k==1)
	{
		f[x1][y1][x2][y2][k]=cal(x1,y1,x2,y2)*cal(x1,y1,x2,y2);
		return f[x1][y1][x2][y2][k];
	}
	int minn=inf;
	//vertical
	for (int i=y1+1;i<=y2;i++)
		for (int j=1;j<k;j++)
		{
			int ma=max(j,k-j),mi=min(j,k-j);
			if (ok(x1,y1,x2,i-1,ma))
				minn=min(minn,dp(x1,y1,x2,i-1,ma)+dp(x1,i,x2,y2,mi));
			if (ok(x1,i,x2,y2,ma))
				minn=min(minn,dp(x1,y1,x2,i-1,mi)+dp(x1,i,x2,y2,ma));
	    }
	//horizontal
	for (int i=x1+1;i<=x2;i++)
		for (int j=1;j<k;j++)
		{
			int ma=max(j,k-j),mi=min(j,k-j);
		    if (ok(x1,y1,i-1,y2,ma))
				minn=min(minn,dp(x1,y1,i-1,y2,ma)+dp(i,y1,x2,y2,mi));
		    if (ok(i,y1,x2,y2,ma))
			    minn=min(minn,dp(i,y1,x2,y2,ma)+dp(x1,y1,i-1,y2,mi));
	    }
	return f[x1][y1][x2][y2][k]=minn;
}
int main()
{
        scanf("%d%d%d",&a,&b,&n);
	for (int i=1;i<=a;i++)
		for (int j=1;j<=b;j++)
			scanf("%d",&x[i][j]),pre[i][j]=pre[i][j-1]+x[i][j];
	for (int i=2;i<=a;i++)
		for (int j=1;j<=b;j++)
			pre[i][j]+=pre[i-1][j];
	memset(f,-1,sizeof(f));
	dp(1,1,a,b,n);
	double ans=0.0;
	ans=(double)f[1][1][a][b][n]/(double)n-(double)(pre[a][b]*pre[a][b])/(double)(n*n);
	printf("%.2lf\n",sqrt(ans));
	return 0;
}

其实这道题一开始wa了无数次。。

我曾经做过poj1191

棋盘分割

Time Limit: 1000MS   Memory Limit: 10000K
Total Submissions: 12647   Accepted: 4481

Description

将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)

原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。

均方差,其中平均值,xi为第i块矩形棋盘的总分。

请编程对给出的棋盘及n,求出O‘的最小值。

Input

第1行为一个整数n(1 < n < 15)。

第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。

Output

仅一个数,为O‘(四舍五入精确到小数点后三位)。

Sample Input

3
1 1 1 1 1 1 1 3
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 0
1 1 1 1 1 1 0 3

Sample Output

1.633

和这道题超级像。。

但是如果你仔细观察会发现不同。

poj这道题切完一刀之后,只能对其中一块进行分割!!而bzoj这道可以对两块进行分割!!

因此poj这道不需要枚举分割的块数。其中一个是1,另一个是k-1!!

时间: 2024-10-29 03:29:45

【BZOJ 1048】 [HAOI2007]分割矩阵的相关文章

BZOJ 1048 [HAOI2007]分割矩阵

1048: [HAOI2007]分割矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 623  Solved: 449[Submit][Status][Discuss] Description 将一个a*b的数字矩阵进行如下分割:将原矩阵沿某一条直线分割成两个矩阵,再将生成的两个矩阵继续如此分割(当然也可以只分割其中的一个),这样分割了(n-1)次后,原矩阵被分割成了n个矩阵.(每次分割都只能沿着数字间的缝隙进行)原矩阵中每一位置上有一个分值,

[BZOJ 1048] [HAOI2007] 分割矩阵 【记忆化搜索】

题目链接:BZOJ - 1048 题目分析 感觉这种分割矩阵之类的题目很多都是这样子的. 方差中用到的平均数是可以直接算出来的,然后记忆化搜索 Solve(x, xx, y, yy, k) 表示横坐标范围 [x, xx], 纵坐标范围 [y, yy] 的矩阵切成 k 块的最小 sigma((Vi - Ave)^2) . 然后再递归将矩阵分得更小,直到 k 为 1 的时候直接返回相应的值. 代码 #include <iostream> #include <cstdlib> #incl

【BZOJ】1048: [HAOI2007]分割矩阵

http://www.lydsy.com/JudgeOnline/problem.php?id=1048 给出一个a×b(a,b<=10)的矩阵,带一个<=100的权值,现在要切割n-1次变成n个矩形(n<=10),求 $$\sqrt{\frac{1}{n}\sum_{i=1}^{n}(sum[i]-\mu)}, \mu = \frac{\sum_{i=1}^{n} sum[i]}{n}, sum[i]表示矩阵的和$$ 的最小值 #include <cstdio> #incl

1048: [HAOI2007]分割矩阵

Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1184  Solved: 863[Submit][Status][Discuss] Description 将一个a*b的数字矩阵进行如下分割:将原矩阵沿某一条直线分割成两个矩阵,再将生成的两个矩阵继续如此分割(当然也可以只分割其中的一个),这样分割了(n-1)次后,原矩阵被分割成了n个矩阵.(每次分割都只能沿着数字间的缝隙进行)原矩阵中每一位置上有一个分值,一个矩阵的总分为其所含各位置上分值之和.

1048: [HAOI2007]分割矩阵——记忆化搜索

http://www.lydsy.com/JudgeOnline/problem.php?id=1048 TML了一发 #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <algorithm> #define clr(a,b) memset(a,b,sizeof(a)) const double INF = 0x3f3f3f3f;

BZOJ-1048: [HAOI2007]分割矩阵 (记忆化搜索)

1048: [HAOI2007]分割矩阵 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1040  Solved: 751[Submit][Status][Discuss] Description 将一个a*b的数字矩阵进行如下分割:将原矩阵沿某一条直线分割成两个矩阵,再将生成的两个矩阵继续如此分割(当然也可以只分割其中的一个),这样分割了(n-1)次后,原矩阵被分割成了n个矩阵.(每次分割都只能沿着数字间的缝隙进行)原矩阵中每一位置上有一个分值

BZOJ1048: [HAOI2007]分割矩阵

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=1048 题解:搞清题意之后来个记忆化爆搜就行了. 代码: 1 #include<cstdio> 2 3 #include<cstdlib> 4 5 #include<cmath> 6 7 #include<cstring> 8 9 #include<algorithm> 10 11 #include<iostream> 12 13

P2217 [HAOI2007]分割矩阵

传送门 首先均方差公式: $\sigma = \sqrt{\sum_{i}^{K}\frac{(sum[i]-\bar{sum})^2}{n}}$ 其中 $\bar{sum}$ 为小矩阵的平均值,显然 $\bar{sum}=\frac{\sum_{i}^{K}sum[i]}{K}$ 所以就是要最小化 $(sum[i]-\bar{sum})^2$ 看到数据这么小,搜就完事了 直接 $dfs(xa,ya,xb,yb,k)$ 表示以 $(xa,ya)$ 为左下角,$(xb,yb)$ 为右上角的子矩阵内

【BZOJ】【1048】【HAOI2007】分割矩阵

DP/记忆化搜索 暴力枚举分割方案?……大概是指数级的?大约是20!的方案= =? 但是我们看到a.b.n的范围都很小……所以不同的状态数只是$10^5$级别的,可以记忆化搜索求解 比较水的一道题…… 1 /************************************************************** 2 Problem: 1048 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:132 ms 7 Me