POJ 1191 棋盘分割 DP

本文探讨了一种使用动态规划解决特定矩阵划分问题的方法。通过定义清晰的状态转移方程,作者详细介绍了如何避免常见的错误,并提供了实现代码示例。特别关注了如何找到正确的子问题以确保解决方案的有效性和正确性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

我做DP的时候一般总是想怎么用状态把问题描述清楚,一般我认为状态描述清楚了,DP就顺利成章的写出来了。

这个题,虽然我想了一会便想到 dp[i][x1][y1][x2][y2] 用这个来描述状态。

但是我的子问题却没有想清楚,结果就使得自己的状态转移方程犯了错。

一开始我是从上往下的,没有考虑下面的应该是最小才能这样,结果就错了。

我的做法是可以,但是要改成记忆化搜索才好做,因为要得到下面的最小值,才能得到这一层的最小值。

另外,这道题的公式转换还是值得注意。

一堆 FOR 循环,实在受不了

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <cmath>
using namespace std;
#define INF 0x3f3f3f3f
#define FOR(a,b) for(int a=0;a<b;a++)
double dp[16][10][10][10][10];
double b[10][10];
double sum[10][10];
double getSum(int x1,int y1,int x2,int y2)
{
	double t=sum[x2][y2]+sum[x1-1][y1-1]-sum[x2][y1-1]-sum[x1-1][y2];
	return t*t;
}
double square(double a)
{
	return a*a;
}
int main()
{
	int n;
	freopen("acm.in","r",stdin);
	while(scanf("%d",&n)!=EOF)
	{
		memset(sum,0,sizeof(sum));

		FOR(i,16)FOR(j,10)FOR(k,10)FOR(l,10)FOR(m,10) 
			dp[i][j][k][l][m]=INF*1.0;

		double tol=0.0;

		for(int i=1;i<=8;i++)
			for(int j=1;j<=8;j++)
			{
				scanf("%lf",&b[i][j]);
				tol+=b[i][j];
			}

		double avg=tol/(n*1.0);

		for(int i=1;i<=8;i++)
			for(int j=1;j<=8;j++)
				sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+b[i][j];

		FOR(j,9)FOR(k,9)FOR(l,9)FOR(m,9) 
		{
			if(!(j&&k&&l&&m)) continue;
			dp[0][j][k][l][m]=getSum(j,k,l,m);
		}

		for(int i=1;i<=n-1;i++)
		{
			for(int j=1;j<8;j++)
			for(int k=1;k<8;k++)
			for(int l=j+1;l<=8;l++)
			for(int m=k+1;m<=8;m++)
			{
				double &cur=dp[i][j][k][l][m];
				for(int q=j;q<l;q++)
				{
					double t=min(dp[i-1][j][k][q][m]+getSum(q+1,k,l,m),dp[i-1][q+1][k][l][m]+getSum(j,k,q,m));
					cur=min(cur,t);
				}
				for(int q=k;q<m;q++)
				{
					double t=min(dp[i-1][j][k][l][q]+getSum(j,1+q,l,m),dp[i-1][j][1+q][l][m]+getSum(j,k,l,q));
					cur=min(t,cur);
				}
			}
		}
		double ans=INF*1.0;
		ans=dp[n-1][1][1][8][8];
		printf("%.3f",sqrt(ans/n-tol*tol/((double)n*n)));
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值