poj1191 棋盘分割区间DP记忆化搜索
Posted wyboooo
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj1191 棋盘分割区间DP记忆化搜索相关的知识,希望对你有一定的参考价值。
棋盘分割
Time Limit: 1000MS | Memory Limit: 10000K | |
Total Submissions: 16263 | Accepted: 5812 |
Description
将一个8*8的棋盘进行如下分割:将原棋盘割下一块矩形棋盘并使剩下部分也是矩形,再将剩下的部分继续如此分割,这样割了(n-1)次后,连同最后剩下的矩形棋盘共有n块矩形棋盘。(每次切割都只能沿着棋盘格子的边进行)
原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差,其中平均值,xi为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O‘的最小值。
原棋盘上每一格有一个分值,一块矩形棋盘的总分为其所含各格分值之和。现在需要把棋盘按上述规则分割成n块矩形棋盘,并使各矩形棋盘总分的均方差最小。
均方差,其中平均值,xi为第i块矩形棋盘的总分。
请编程对给出的棋盘及n,求出O‘的最小值。
Input
第1行为一个整数n(1 < n < 15)。
第2行至第9行每行为8个小于100的非负整数,表示棋盘上相应格子的分值。每行相邻两数之间用一个空格分隔。
第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
Source
题意:
一个8*8的棋盘,进行分割。每次将一个矩形分割成两个。一个矩形的值是里面所有格子值之和。现在想切出n个矩形,希望求得最小的均方差。
思路:
我们先把均方差的公式进行化简
平均值是一个定值,因为每个矩形都是格子值之和。于是我们发现结果之和Xi平方有关。Xi平方越小越好。
对于每一个格子,都可以用两个坐标(i, j)和(x,y)表示,他们分别是矩形的左上角和右下角。
一个矩形有两种切割方法,横着切,竖着切,假设在k处切
横着切时,矩形被分成了(i, j)(k, y) 和 (k + 1, j)(x,y)
竖着切时,矩形被分成了(i,j)(x,k) 和(i, k+1)(x,y)
但是这样还没办法进行状态转移,因为矩形的先后顺序不知道。所以我们可以再引入一维变量,表示各自的顺序。
于是在切割i次时,得到两个矩形,其中一个应该是i+1次切割的矩形。可以得到状态转移方程。
因为是i推i+1,所以用记忆化搜索写起来可能方便一点
1 //#include <bits/stdc++.h> 2 #include<iostream> 3 #include<cmath> 4 #include<algorithm> 5 #include<stdio.h> 6 #include<cstring> 7 #include<vector> 8 #include<map> 9 #include<set> 10 11 #define inf 0x3f3f3f3f 12 using namespace std; 13 typedef long long LL; 14 15 int n; 16 int board[10][10], hang[10][10], dp[20][10][10][10][10]; 17 18 /*int getval(int i, int j, int x, int y) 19 { 20 int res = 0; 21 for(int k = i; k <= x; k++){ 22 res += hang[i][y] - hang[i][j - 1]; 23 } 24 return res * res; 25 }*/ 26 27 int getval(int i, int j, int x, int y) 28 { 29 int res = 0; 30 for(int a = i; a <= x; a++){ 31 for(int b = j; b <= y; b++){ 32 res += board[a][b]; 33 } 34 } 35 return res * res; 36 } 37 38 int DP(int k, int i, int j, int x, int y) 39 { 40 int ans = 0; 41 if(dp[k][i][j][x][y] >= 0)return dp[k][i][j][x][y]; 42 if(k == n - 1){ 43 return getval(i, j, x, y); 44 } 45 dp[k][i][j][x][y] = inf; 46 for(int tmp = i; tmp < x; tmp++){ 47 ans = min(DP(k + 1, i, j, tmp, y) + getval(tmp + 1, j, x, y), DP(k + 1, tmp + 1, j, x, y) + getval(i, j, tmp, y)); 48 dp[k][i][j][x][y] = min(ans, dp[k][i][j][x][y]); 49 } 50 for(int tmp = j; tmp < y; tmp++){ 51 ans = min(DP(k + 1, i, j, x, tmp) + getval(i, tmp + 1, x, y), DP(k + 1, i, tmp + 1, x, y) + getval(i, j, x, tmp)); 52 dp[k][i][j][x][y] = min(ans, dp[k][i][j][x][y]); 53 } 54 return dp[k][i][j][x][y]; 55 } 56 57 int main(){ 58 59 while(scanf("%d", &n) != EOF){ 60 double sum = 0; 61 memset(hang, 0, sizeof(hang)); 62 for(int i = 1; i <= 8; i++){ 63 for(int j = 1; j <= 8; j++){ 64 scanf("%d", &board[i][j]); 65 sum += board[i][j] * 1.0; 66 hang[i][j] = hang[i][j - 1] + board[i][j]; 67 } 68 } 69 sum /= 1.0 * n; 70 memset(dp, -1, sizeof(dp)); 71 int ans = DP(0, 1, 1, 8, 8); 72 //cout<<ans<<endl; 73 //cout<<dp[n - 1][1][1][8][8]<<endl; 74 printf("%.3f ",sqrt((dp[0][1][1][8][8])*1.0/n-sum*sum)); 75 } 76 return 0; 77 }
以上是关于poj1191 棋盘分割区间DP记忆化搜索的主要内容,如果未能解决你的问题,请参考以下文章