POJ 1191 棋盘分割
2012-06-26 19:07
357 查看
题目连接:http://poj.org/problem?id=1191
解题思路:
棋盘分割一块之后,剩余的棋盘的分割和原问题类似,只是规模变小了。棋盘分割问题可以采用动态规划方法解决。
对方差公式进行化解,得到σ^2=1/n∑xi^2 - x^2
可知,要使方差最小,只需使∑xi^2最小即可,即各块分值平方和最小。平均值 x是个固定的数,跟分割的方式没有关系,
首先定义状态:dp[k][x1][y1][x2][y2],表示左上角坐标(x1,y1)到右下角坐标(x2,y2)区域的棋盘经过k次分割后,各块分值平方和的最小值。则状态转移方程为:
dp[k][x1][y1][x2][y2] = min{
dp[0][x1][y1][t][y2]+dp[k-1][t+1][y1][x2][y2], (x1 <= t < x2)
dp[k-1][x1][y1][t][y2]+dp[0][t+1][y1][x2][y2], (x1 <= t < x2) //竖切
dp[0][x1][y1][x2][t]+dp[k-1][x1][t+1][x2][y2], (y1 <= t < y2)
dp[k-1][x1][y1][x2][t]+dp[0][x1][t+1][x2][y2] (y1 <= t < y2) //横切
}
dp[0][x1][y1][x2][y2]表示左上角坐标(x1,y1)到右下角坐标(x2,y2)区域的棋盘的分值和平方
有了状态转移方程后,就很容易写出代码了,开始dp数组使用long double,提交后WA,改成double后就AC了,很奇怪。
代码:
解题思路:
棋盘分割一块之后,剩余的棋盘的分割和原问题类似,只是规模变小了。棋盘分割问题可以采用动态规划方法解决。
对方差公式进行化解,得到σ^2=1/n∑xi^2 - x^2
可知,要使方差最小,只需使∑xi^2最小即可,即各块分值平方和最小。平均值 x是个固定的数,跟分割的方式没有关系,
首先定义状态:dp[k][x1][y1][x2][y2],表示左上角坐标(x1,y1)到右下角坐标(x2,y2)区域的棋盘经过k次分割后,各块分值平方和的最小值。则状态转移方程为:
dp[k][x1][y1][x2][y2] = min{
dp[0][x1][y1][t][y2]+dp[k-1][t+1][y1][x2][y2], (x1 <= t < x2)
dp[k-1][x1][y1][t][y2]+dp[0][t+1][y1][x2][y2], (x1 <= t < x2) //竖切
dp[0][x1][y1][x2][t]+dp[k-1][x1][t+1][x2][y2], (y1 <= t < y2)
dp[k-1][x1][y1][x2][t]+dp[0][x1][t+1][x2][y2] (y1 <= t < y2) //横切
}
dp[0][x1][y1][x2][y2]表示左上角坐标(x1,y1)到右下角坐标(x2,y2)区域的棋盘的分值和平方
有了状态转移方程后,就很容易写出代码了,开始dp数组使用long double,提交后WA,改成double后就AC了,很奇怪。
代码:
#include <iostream> #include <cstdio> #include <cmath> #include <iomanip> using namespace std; int data[9][9]; int sum[9][9]; double dp[14][9][9][9][9]; //返回左上角坐标(x1,y1)到右下角坐标(x2,y2)区域的棋盘的分值和平方 double count(int x1, int y1, int x2, int y2) { double ans = (double)(sum[x2][y2]-sum[x1-1][y2]-sum[x2][y1-1]+sum[x1-1][y1-1]); return ans*ans; } int main() { int n, total=0; //输入数据 cin>>n; for(int i=1; i<=8; ++i) for(int j=1; j<=8; ++j) { cin>>data[i][j]; //sum[i][j]表示棋盘(1,1)到(i,j)区域的累计分值 sum[i][j] = sum[i][j-1] + sum[i-1][j] - sum[i-1][j-1] + data[i][j]; //total表示整个棋盘的分值之和 total += data[i][j]; } //初始化dp数组 for(int x1=1; x1<=8; ++x1) for(int y1=1; y1<=8; ++y1) for(int x2=x1; x2<=8; ++x2) for(int y2=y1; y2<=8; ++y2) dp[0][x1][y1][x2][y2] = count(x1,y1,x2,y2); //自底向上计算dp数据 for(int k=1; k<n; ++k) for(int x1=1; x1<=8; ++x1) for(int y1=1; y1<=8; ++y1) for(int x2=x1; x2<=8; ++x2) for(int y2=y1; y2<=8; ++y2) { int t; dp[k][x1][y1][x2][y2] = (double)(1<<30); for(t=x1; t<x2; ++t) { dp[k][x1][y1][x2][y2] = min(dp[k][x1][y1][x2][y2], dp[0][x1][y1][t][y2]+dp[k-1][t+1][y1][x2][y2]); dp[k][x1][y1][x2][y2] = min(dp[k][x1][y1][x2][y2], dp[k-1][x1][y1][t][y2]+dp[0][t+1][y1][x2][y2]); } for(t=y1; t<y2; ++t) { dp[k][x1][y1][x2][y2] = min(dp[k][x1][y1][x2][y2], dp[0][x1][y1][x2][t]+dp[k-1][x1][t+1][x2][y2]); dp[k][x1][y1][x2][y2] = min(dp[k][x1][y1][x2][y2], dp[k-1][x1][y1][x2][t]+dp[0][x1][t+1][x2][y2]); } } //计算方差平方 double ans = dp[n-1][1][1][8][8]*1.0/n - ((double)total*1.0/n)*((double)total*1.0/n); //输出方差,精确到小数点后三位 cout<<setprecision(3)<<fixed<<sqrt(ans)<<endl; return 0; }
相关文章推荐
- poj1191-dp棋盘分割
- POJ 1191 棋盘分割【区间类DP】
- POJ1191 棋盘分割(DP)
- OpenJudge/Poj 1191 棋盘分割
- poj 1191 棋盘分割(dp,黑书dp例二)
- POJ 1191 棋盘分割(DP)
- POJ 1191 棋盘分割
- poj 1191 棋盘分割 动态规划
- poj 1191 棋盘分割
- poj 1191 棋盘分割 公式转换,横纵方向动态规划
- poj - 1191 - 棋盘分割(dp)
- poj-1191- 棋盘分割dp
- POJ 1191 棋盘分割 中文
- poj 1191 棋盘分割 (dfs)
- POJ 1191 棋盘分割
- POJ 1191 棋盘分割
- poj 1191棋盘分割
- poj 1191 棋盘分割
- poj 1191 棋盘分割
- poj 1191 棋盘分割