实验四 动态规划算法设计与应用实验报告

一. 实验目的和要求
1.加深对动态规划算法的基本原理的理解,掌握用动态规划方法求解最优化问题的方法步骤及应用;
2.用动态规划设计整数序列的最长递增子序列问题的算法,分析其复杂性,并实现;
3.用动态规划设计求凸多边形的三角剖分问题的算法,分析其复杂性,并实现。
4.选做题:用动态规划设计求解0/1背包问题的算法,分析其复杂性,并实现。
二. 实验步骤

实验一: 最长递增子序列问题:
问题描述:
求一个由n个整数组成的整数序列的最长递增子序列。一个整数序列的递增子序列可以是序列中非连续的数按照原序列顺序排列而成的。 最长递增子序列是其递增子序列中长度最长的。

  1. 问题分析
    给你n个数,让你求出他的最长上升子序列(LIS),并输出最长的序列
    几个数。考虑用动态规划解决,首先可以考虑 O ( n 2 ) O(n^2) O(n2)的dp, d p [ i ] dp[i] dp[i]表示到第i个数的最长的值,那么我们就可以得到转移方程 d p [ i ] = m a x ( d p [ i ] , d p [ j ] + 1 ) ; dp[i] = max(dp[i],dp[j] + 1); dp[i]=max(dp[i],dp[j]+1);最后对dp遍历找出最大的值即可。用pre数组记录序列数的下标,转置输出即可。
    当然还有复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)的方法,即用一个tmp数组来存目前的排序好的数组,然后每次lower_bound出位置即为最大上升序列的位置,即为dp[i]的值。但是这种方法对于记录下标依然是 O ( n 2 ) O(n^2) O(n2)的复杂度。

2.设计与实现

#include
#define mes(a, b)  memset(a, b, sizeof a)
#define pb push_back
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e6 + 20;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;
int dp[maxn],pre[maxn],a[maxn];
std::vector<int> ans;
int main(){
     
	int _;
	for(scanf("%d",&_);_;_--){
     
		ans.clear();	
		mes(dp,0);mes(pre,-1);
		int n;scanf("%d",&n);
		for(int i = 1;i <= n;i++) scanf("%d",&a[i]),dp[i] = 1;
		for(int i = 1;i <= n;i++){
     
			for(int j = 1;j < i;j++){
     
				if(a[i] > a[j]){
     
					if(dp[i] < dp[j] + 1) dp[i] = dp[j] + 1,pre[i] = j;
				}
			}
		}
		int pos,maxx = 0;
		for(int i = 1;i <= n;i++){
     
			if(dp[i] > maxx) maxx = dp[i],pos = i;
		}
		printf("%d\n",maxx);
		for(int i = pos;i != -1;i = pre[i]){
     
			ans.pb(a[i]);
		}
		reverse(ans.begin(), ans.end());
		for(auto it : ans) printf("%d ",it);
		puts("");puts(" ");
	}
}

实验(二) 凸多边形的三角剖分:
问题描述
设P是一个有n个顶点的凸多边形,P中的弦是P中连接两个非相邻顶点的线段。用P中的(n-3)条弦将P剖分成(n-2)个三角形(如下图所示)。使得(n-3)条弦的长度之和最小的三角形剖分称为最优三角剖分。

1.问题分析
要求凸多边形的最优三角剖分,我们先预处理出每个顶点之间的距离,然后考虑区间合并,考虑递归,以i为点的边将凸多边形分为一个三角形和若干个凸多边形,如果k = a + 1,那么剩下的还是一个凸多边形,当k = b – 1时同理,其他情况考虑递归转移式: n u m [ i ] = c a l c ( a , k ) + d i s [ a ] [ k ] + c a l c ( k , b ) + d i s [ k ] [ b ] ; num[i] = calc(a,k) + dis[a][k] + calc(k,b)+dis[k][b]; num[i]=calc(a,k)+dis[a][k]+calc(k,b)+dis[k][b];然后找出最大的num[i]的值即可。复杂度 O ( n 3 ) O(n^3) O(n3)
2.设计与实现

#include
#define mes(a, b)  memset(a, b, sizeof a)
#define pb push_back
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 550 + 20;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;
double dis[maxn][maxn];
double x[maxn],y[maxn];
int n;
void init(){
     
	for(int i = 1;i <= n;i++){
     
		for(int j = 1;j <= n;j++){
     
			dis[i][j] = sqrt((x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]));
		}
	}
}
double calc(int b,int c){
     
	double s = INF;std::vector<double> v;
	if(c - b == 2) return 0;
	for(int i = b + 1;i < c;i++){
     
		if(i == b + 1) v.pb(calc(i,c) + dis[b + 1][c]);
		else if(i == c - 1) v.pb(calc(b,i) + dis[b][c - 1]);
		else v.pb(calc(i,c) + calc(b,i) + dis[b][i] + dis[i][c]);
	}
	for(auto it : v) s = min(it,s);
	return s;
}
int main(){
     
	int _;
	for(scanf("%d",&_);_;_--){
     
		scanf("%d",&n);
		for(int i = 1;i <= n;i++) scanf("%lf %lf",&x[i],&y[i]);
		init();
		printf("%.3f\n",calc(1,n));
	}
}

实验(三) 选做题――0/1背包问题:
问题描述
设有一个容量为C的背包,n个物品的集合U={u1, u2, …, un},物品uj的体积和价值分别为sj和vj,C, sj, vj都是正整数。在U中选择物品装入背包,使得装入背包的物品总价值最大。设每种物品或完全装入或完全不装入背包。

1.问题分析
经典的01背包问题,易得转移方程:
d p [ i ] [ j ] = m a x ( d p [ i − 1 ] [ j ] , d p [ i – 1 ] [ j – c [ i ] ] + w [ i ] ) dp[i][j] = max(dp[i- 1][j],dp[i – 1][j – c[i]] + w[i]) dp[i][j]=max(dp[i1][j],dp[i1][jc[i]]+w[i])
记录路径直接用 d p [ ] [ ] dp[][] dp[][]数组求解,看他是从哪个状态转移过来的即可。
当然也可以滚动为一维,也易得
d p [ j ] = m a x ( d p [ j ] , d p [ j – c [ i ] ] + w [ i ] ) ; dp[j] = max(dp[j],dp[j – c[i]] + w[i]); dp[j]=max(dp[j],dp[jc[i]]+w[i]);
但是滚动成一维就无法倒推了。
2.设计与实现

#include
#define mes(a, b)  memset(a, b, sizeof a)
#define pb push_back
typedef unsigned long long int ull;
typedef long long int ll;
const int    maxn = 1e6 + 20;
const int    maxm = 1e5 + 10;
const ll     mod  = 1e9 + 7;
const ll     INF  = 1e18 + 100;
const int    inf  = 0x3f3f3f3f;
const double pi   = acos(-1.0);
const double eps  = 1e-8;
using namespace std;
int dp[110][5100],s[maxn],val[maxn];
set<int>ans;
int _;
int main(){
     
	for(scanf("%d",&_);_;_--){
     
		mes(dp,0);ans.clear();
		int n,c;scanf("%d %d",&n,&c);
		for(int i = 1;i <= n;i++) scanf("%d",&s[i]);
		for(int i = 1;i <= n;i++) scanf("%d",&val[i]);
		for(int i =  1;i <= n;i++){
     
			for(int j = c;j >= 0;j--){
     
				dp[i][j] = dp[i - 1][j];
				if(j < s[i]) continue;
				dp[i][j] = max(dp[i - 1][j],dp[i - 1][j - s[i]] + val[i]);
			}
		}
		printf("%d\n",dp[n][c]);
		for(int i = n,j = c;i >= 1 && j >= 0;i--){
     
			if(dp[i][j] == dp[i - 1][j - s[i]] + val[i]){
     
				ans.insert(i);j -= s[i];
			}
		}
		for(int i = 1;i <= n;i++) if(ans.count(i)) putchar('1 ');else putchar('0 ');
		puts("");
	}
}

ps:代码基于c++11,无法运行请打开编译器c++11开关

你可能感兴趣的:(实验四 动态规划算法设计与应用实验报告)