区间类动态规划之详解凸多边形的划分

区间动态规划是线性动规的拓展,在划分阶段时,往往是以区间的长度从小到大为阶段,逐步求解到到长度为N的区间的最优值,在枚举每一个区间的最优值时,由于当前区间内又有很多种合并方式并到到当前区间,那么就需要枚举这些合并方式中产生的值维护最优值,合并的不同,可以看作是区间划分的不同,划分时需要枚举划分的位置,即分割点。
  那么对于区间类动态规划问题,往往可以将问题分解成为两两合并的形式。其解决方法是对整个问题设最优解,枚举分割点,维护最优值。
dp[i][j] = max{dp[i][k] + dp[k+1][j] + 合并时需要计算的值 },其中k为区间[i,j]内一分割点。
回到问题凸多边形的划分这道题。
题目描述
  给定一个具有N(N<=50)个顶点(从1到N编号)的凸多边形,每个顶点的权均是一个正整数。问:如何把这个凸多边形划分成N-2个互不相交的三角形,使得这些三角形顶点的权的乘积之和最小?
输入
  输入文件的第一行为顶点数N;第二行为N个顶点(从1到N)的权值。
输出
  只有一行为这些三角形顶点的权的成绩之和的最小值。
样例输入
5
121 122 123 245 231
样例输出
12214884
分析:
对于多边形,我们将其顶点按顺时针编号,那么所求问题为1~n顺时针连线组成的多边形的三角形划分后的权值乘积之和的最小值。按照求什么设什么的思考原则,设dp[i][j](i < j)表示从i~j顺时针连线组成的多边形的三角形剖分后所得的顶点权值乘积和的最小值。
这里写图片描述
我们可以找到一个k,i < k < j,使其将ij所组成的多边形分成3份,剖出来的三份分别是ik构成的多边形,ijk三个点构成的三角形和k~j构成的多边形,如下图所示。
这里写图片描述
那么dp[i][j] = min{ dp[i][k] + a[i] * a[j] * a[k] + dp[k][j] }(1<=i < k < j < = n);
初始dp[i][i+1] = 0;
目标状态在dp[1][n];
这道题涉及到多个三个数的乘积之和,计算结果会非常大,需要使用高精度。
下面给出没有用高精度的50分程序供看官纯粹地去理解动规过程。

#include<bits/stdc++.h>
using namespace std;
long long dp[51][51],a[51];
int main(){
    int n;
    memset(dp,0x7f,sizeof(dp));
    cin >> n;
    for(int i=1;i<= n;i++) cin >> a[i];
    for(int i= 1;i<= n;i++){
        dp[i][i+1] = 0;
    }
    for(int t= 2;t <= n-1;t++){
        for(int i = 1;i<= n-t; i++){
            int j = i + t;
            for(int k = i+1;k<= j-1;k ++){
                dp[i][j] = min(dp[i][j],dp[i][k]+dp[k][j]+1LL*a[i]*a[j]*a[k]); 
            }
        }
    }
    cout << dp[1][n];
    return 0;
}

在最后再上AC程序,写得不好勿喷。

#include<bits/stdc++.h>
using namespace std;
long long a[51];
const int MAXN=202;
struct Bignum{
	int len,s[MAXN*2];
	Bignum(){
		memset(s,0,sizeof(s));
		len = 1;
	}
	Bignum operator +(const Bignum &A)const{
		Bignum B;
		B.len = max(len,A.len);
		for(int i = 0;i< B.len; i++){
			B.s[i] =B.s[i] + A.s[i] + s[i];
			B.s[i+1] += B.s[i]/10;
			B.s[i] = B.s[i]%10;
		}
		if(B.s[B.len]) B.len ++;
		return B;
	}
	bool operator <(const Bignum &A)const{
		if(len != A.len) return len < A.len;
		for(int i= len-1; i >=0 ; i--){
			if(s[i] != A.s[i]) return s[i] < A.s[i];
		}
		return false;
	}
	Bignum operator *(const Bignum &A)const{
		Bignum B;
		B.len = len+A.len-1;
		for(int i = 0;i< A.len; i++){
			for(int j=0;j< len;j++){
				B.s[i+j] =B.s[i+j] + A.s[i] * s[j];
				B.s[i+j+1] += B.s[i+j]/10;
				B.s[i+j] = B.s[i+j]%10;
			}			
		}
		
		if(B.s[B.len]) B.len ++;
		return B;
	}	
	void write(){
		int k = len-1;
		while(s[k]==0 && k >0) k--;
		for(int i = k;i>=0;i--)   cout << s[i];
	} 
}dp[51][51];
Bignum change(long long x){  //将一个整数变成数组存储的Bignum类型 
	Bignum t;
	int cnt =0;
	while(x!=0){
		t.s[cnt++] = x%10;
		x /= 10; 
	}
	t.len = cnt;
	return t;
}
int main(){
	int n;
	cin >> n;
	for(int i=1;i<= n;i++) cin >> a[i];
	for(int t= 2;t <= n-1;t++){ //阶段:枚举连续的t+1个点组成的t+1边形
		for(int i = 1;i<= n-t; i++){  //状态:枚举当前阶段的连续区间的起点 
			int j = i + t;      //计算当前区间的终点 
			dp[i][j].len = 400;  //将dp[i][j]初始化为一个大数 
			dp[i][j].s[399] = 1;
			//枚举k, 其中i<k<j ,  i,j,k构成的三角形将i~j 号点组成的多边形分成三份 
			// 这三份分别是i~k组成的三角形,ijk三个点组成的一个三角形和k~j组成的多边形。 
			for(int k = i+1;k<= j-1;k ++){	
			    //注意a[i]*a[j]*a[k]会比较大,此处也需要高精度, 							
				Bignum t = change(a[i]) * change(a[j]) * change(a[k]);
				Bignum tp = dp[i][k] + dp[k][j] + t;
				if(tp < dp[i][j]) dp[i][j] = tp;
			}
		}
	}	
	dp[1][n].write();
	return 0;
}
  • 10
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
SGBM算法中的动态规划部分是指SGM算法(Semi-Global Matching)的实现。在SGBM算法中,首先通过计算代价图来获取初始的视差图。然后,利用动态规划的思想对初始视差图进行优化,以得到更准确的视差图。 动态规划是一种优化问题的常用方法,它通过将问题分解为子问题,并利用子问题的最优解来求解整个问题的最优解。在SGBM算法中,动态规划被用于对每个像素的视差值进行优化。 具体来说,SGBM算法中的动态规划部分包括以下几个步骤: 1. 定义代价函数:根据图像的亮度差异等因素,定义一个代价函数来衡量不同视差值的匹配程度。 2. 计算代价图:对于每个像素,计算其与邻域像素的代价值,并将这些代价值组成一个代价图。 3. 动态规划优化:利用动态规划的思想,从左到右和从上到下遍历代价图,通过比较当前像素与其左侧和上方像素的代价值,选择最小的代价值作为当前像素的最优视差值。 4. 反向传播:从右下角开始,从右到左和从下到上遍历代价图,通过比较当前像素与其右侧和下方像素的代价值,进一步优化当前像素的最优视差值。 5. 视差平滑:为了进一步提高视差图的质量,可以对最终的视差图进行平滑处理,以减少噪声和不连续性。 通过以上步骤,SGBM算法能够对初始视差图进行优化,得到更准确的视差图。这样可以提高立体匹配的效果,使得物体的深度信息更加准确可靠。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值