poj解题报告——1191

本文探讨了一道复杂的动态规划题目,目标是最小化切割后的矩形总分平方和。通过递归划分策略,利用状态转移方程实现最优解搜索,并提供完整代码实现。

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

        这题动态规划,太难了,参考了别人的思路,写了这份报告。

        分析一下,根据题意,要求均方差ans = sqrt(Sum((x[i]-x的平均值)^2)/n),ans^2=Sum(x[i]*x[i])/n-(x的平均值)^2,而x的平均值是固定值(即所有方格数字的和/n),所以只要使得切割后的矩形的总分的平方和尽量小,由于切割只能沿着棋盘的边进行,故对于左上角坐标为[x1,y1],右下角坐标[x2,y2]的棋盘,可以沿着横线切或者沿着竖线切,如用dp[n][x1][y1][x2][y2]表示将上述矩形切割为n个时的矩形的总分的最小平方和,则有在横向有状态转移方程:dp[n][x1][y1][x2][y2] = Min((dp[n][x1][y1][i][y2]+sum(i+1,y1,x2,y2)))

代码如下

#include<stdio.h>
#include<math.h>
#define N 9
#define D 16
#define INF 9999999
int dp[D][N][N][N][N];
int s[N][N][N][N];
int a[N][N];
int n;
int Sum(int x1,int y1,int x2,int y2)
{
	int ans=0;
	int i,j;
	if(s[x1][y1][x2][y2]>0)
		return s[x1][y1][x2][y2];
	for(i=x1;i<=x2;i++)
	{
		for(j=y1;j<=y2;j++)
			ans+=a[i][j];
	}
	s[x1][y1][x2][y2]=ans*ans;
	return s[x1][y1][x2][y2];
}
int Divide(int n,int x1,int y1,int x2,int y2)
{
	int min,i,j,m;
	if(n==1)
	{
		if(dp[n][x1][y1][x2][y2]==-1)
			dp[n][x1][y1][x2][y2]=Sum(x1,y1,x2,y2);
		return dp[n][x1][y1][x2][y2];
	}
	if(dp[n][x1][y1][x2][y2]!=-1)
		return dp[n][x1][y1][x2][y2];
	min=INF;
	for(i=x1;i<x2;i++)
	{
		m=Divide(n-1,x1,y1,i,y2)+Sum(i+1,y1,x2,y2);
		if(min>m)
			min=m;
		m=Divide(n-1,i+1,y1,x2,y2)+Sum(x1,y1,i,y2);
		if(min>m)
			min=m;
	}
	for(j=y1;j<y2;j++)
	{
		m=Divide(n-1,x1,y1,x2,j)+Sum(x1,j+1,x2,y2);
		if(min>m)
			min=m;
		m=Divide(n-1,x1,j+1,x2,y2)+Sum(x1,y1,x2,j);
		if(min>m)
			min=m;
	}
	dp[n][x1][y1][x2][y2]=min;
	return min;
}
void main()
{
	int i,j;
	double sum=0.0,ans;
	scanf("%d",&n);
	for(i=1;i<N;i++)
	{
		for(j=1;j<N;j++)
		{
			scanf("%d",&a[i][j]);
			sum+=a[i][j];
		}
	}
	sum/=n;
	memset(dp,-1,sizeof(dp));
	memset(s,0,sizeof(s));
	ans=Divide(n,1,1,N-1,N-1);
	ans=sqrt(ans/n-sum*sum);
	printf("%.3lf\n",ans);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值