poj 1191 棋盘分割 (DFS+DP思想)
2013-06-04 23:05
459 查看
http://poj.org/problem?id=1191
棋盘分割
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
Sample Output
实现代码:
棋盘分割
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 10776 | Accepted: 3791 |
将一个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 思路: 根据题目给出的公式进行化简: σ=sqrt(((x1-x)^2+(x2-x)^2+...+(xn-x)^2)/n),其中x为x1..xn的平均数. 所以σ^2=((x1-x)^2+(x2-x)^2+...+(xn-x)^2)/n 即n*σ^2=(x1-x)^2+(x2-x)^2+...+(xn-x)^2 =x1^2-2x*x1+x^2+x2^2-2x*x2+x^2+...+xn^2-2x*xn+x^2 =x1^2+x2^2+...+xn^2-2x(x1+x2+...+xn)+n*x^2 =x1^2+x2^2+...+xn^2-2x*n*x+n*x^2 =x1^2+x2^2+...+xn^2-n*x^2 即n*σ^2+n*x^2=x1^2+x2^2+...+xn^2. n*σ^2+n*x^2中n和x都是一定的,所以只要x1^2+x2^2+...+xn^2最小则σ最小 关于快速计算 左上角为(x1, y1),右下角为(x2, y2)的矩阵的大小:
实现代码:
#include<iostream> #include<stdio.h> #include<string.h> #include<math.h> #include<queue> #define SIZE 8 #define INF 99999999 using namespace std; int map[SIZE+1][SIZE+1]; //存所有矩形 int mark[16][SIZE+1][SIZE+1][SIZE+1][SIZE+1]; int sum[SIZE+1][SIZE+1];//sum中每一个位置存放的是左上角为(1,1)点与右下角为当前位置的矩形的所有元素的和,这里下标从1开始 int min(int a,int b){return a<b?a:b;} //计算:左上角为(x1, y1),右下角为(x2, y2)的矩阵平方 int powsum(int x1,int y1,int x2,int y2) { int res; res=sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]; return res*res; } //深度搜索,计算最小平方和 int dfs(int deep,int x1,int y1,int x2,int y2) { if(mark[deep][x1][y1][x2][y2]!=-1) { return mark[deep][x1][y1][x2][y2]; //已经计算过了的避免重复计算,也就是传说中的剪枝 } else { if(deep==1||x1==x2||y1==y2) { return mark[deep][x1][y1][x2][y2]=powsum(x1,y1,x2,y2); //当无法再切直接返回 } else { int i,maks=INF; //给maks初始化一个足够大的值 for(i=x1;i<x2;i++) //横切 { maks=min(maks,min(dfs(deep-1,x1,y1,i,y2)+powsum(i+1,y1,x2,y2),dfs(deep-1,i+1,y1,x2,y2)+powsum(x1,y1,i,y2))); } for(i=y1;i<y2;i++) //竖切 { maks=min(maks,min(dfs(deep-1,x1,y1,x2,i)+powsum(x1,i+1,x2,y2),dfs(deep-1,x1,i+1,x2,y2)+powsum(x1,y1,x2,i))); } mark[deep][x1][y1][x2][y2]=maks; return maks; } } } int main() { int n; while(~scanf("%d",&n)) { int i,j; memset(map,0,sizeof(map)); memset(sum,0,sizeof(sum)); for(i=1;i<=SIZE;i++) { for(j=1;j<=SIZE;j++) { scanf("%d",&map[i][j]); sum[i][j]=sum[i][j-1]+sum[i-1][j]-sum[i-1][j-1]+map[i][j]; // 计算是左上角为(1,1)点与右下角(i,j)的矩形的所有元素的和 } } memset(mark,-1,sizeof(mark)); double res=sqrt((double)(dfs(n,1,1,SIZE,SIZE))/n-pow((double)(sum[SIZE][SIZE])/n,2.0)); //展开化简之后的公式 printf("%.3lf\n",res); } return 0; }
相关文章推荐
- POJ 1191 棋盘分割 (DP)
- POJ 1191 棋盘分割(DP)
- poj 1191 棋盘分割 (dfs)
- POJ 1191 棋盘分割 DP
- POJ 1191 棋盘分割(DP)
- POJ 1191 棋盘分割【区间类DP】
- 经典问题六.【二维的区间dp】棋盘分割 poj 1191
- (POJ 1191)棋盘分割 <DFS>
- poj-1191- 棋盘分割dp
- poj 1191 棋盘分割(DP)
- POJ 1191 && HDU 2517 棋盘分割(dp)
- poj 1191棋盘分割(递归dp, 记忆化搜索)
- poj1191 棋盘分割 dp
- poj1191--棋盘分割(dp)
- poj-1191- 棋盘分割dp
- 棋盘分割----POJ1191----DP
- 【DP】 POJ 1191 棋盘分割 记忆化搜索
- POJ 1191 DP+DFS棋盘分割问题
- 【DP】 POJ 1191 棋盘分割 记忆化搜索
- poj 1191 棋盘分割 (dp)