P1759 通天之潜水(双写法+解析)

算法解析

动态规划问题满足三大重要性质

最优子结构性质:如果问题的最优解所包含的子问题的解也是最优的,我们就称该问题具有最优子结构性质(即满足最优化原理)。最优子结构性质为动态规划算法解决问题提供了重要线索。

子问题重叠性质:子问题重叠性质是指在用递归算法自顶向下对问题进行求解时,每次产生的子问题并不总是新问题,有些子问题会被重复计算多次。动态规划算法正是利用了这种子问题的重叠性质,对每一个子问题只计算一次,然后将其计算结果保存在一个表格中,当再次需要计算已经计算过的子问题时,只是在表格中简单地查看一下结果,从而获得较高的效率。

无后效性:将各阶段按照一定的次序排列好之后,对于某个给定的阶段状态,它以前各阶段的状态无法直接影响它未来的决策,而只能通过当前的这个状态。换句话说,每个状态都是过去历史的一个完整总结。这就是无后向性,又称为无后效性。

P1759 通天之潜水

题目

在猴王的帮助下,小A终于走出了这篇荒山,却发现一条波涛汹涌的河拦在了自己的面前。河面上并没有船,但好在小A有\(n\)个潜水工具。由于他还要背重重的背包,所以他只能背\(m\)重的工具,又因为他的力气并不是无限的,河却很宽,所以他只能背有\(v\)阻力的工具。但是这条河下有非常重要的数据,所以他希望能够停留的时间最久。于是他找到了你,让你告诉他方案。

输入

三个数\(m,v,n\)如题目所说
接下来n行,每行三个数\(ai,bi,ci\)分别表示所含的重力,阻力,能够支撑的时间

输出

第一行一个数,表示最长的时间
接下来一行,若干个数,表示所选的物品

样例

100 100 3                                       405
50 60 289                                       1 2
40 10 116
50 50 106

解析

刚开始看的时候还行,看到要输出所选的物品的时候呆了,想到两种方法
\(First\)是用f[i][j]算最大时间,用三维数组p[i][j][k]表示 第\(i\)个物品在有\(j\)重力\(k\)阻力时是否选这个工具,顺着数组递归输出选的工具
\(Second\)是用DFS 应为数据比较小,不用剪枝也可以过

代码

//第一组
#include <bits/stdc++.h>
#define N 10005
using namespace std;
int f[N][N];
int w[N],v[N],t[N];
bool p[105][205][205];
void print(int date,int m,int s){
	if (date==1){
		if (p[date][m][s]==true)
			printf("1 ");
		return;
	}else if (p[date][m][s]==true){
		print(date-1,m-w[date],s-v[date]);
		printf("%d ",date);
	}else {
		print(date-1,m,s);
	}return;
}
int main(){
	int m,s,n;
	scanf("%d%d%d",&m,&s,&n);
	f[0][0]=0;
	for (int i=1;i<=n;i++){
		scanf("%d%d%d",&w[i],&v[i],&t[i]);
	}
	for (int l=1;l<=n;l++){
		for (int i=m;i>=w[l];i--){
			for (int j=s;j>=v[l];j--){
				if (f[i][j]<f[i-w[l]][j-v[l]]+t[l]){
					f[i][j]=f[i-w[l]][j-v[l]]+t[l];
					p[l][i][j]=true;	
				}
				
			}
		}
	}
	printf("%d\n",f[m][s]);
	print(n,m,s);
	return 0;
}

———————————————————————————一点也不美丽的华丽分割线———————————————————————————————

//第二个
#include <bits/stdc++.h>
using namespace std;
int m,v,n,a[105],b[105],c[105];
int ans,r[105],cs[105],cho;
void dfs(int Nans,int date,int m,int v,int h){
	if (m<0||v<0)return;
	if (Nans>ans){
		ans=Nans;cho=h;
		for (int i=1;i<=h;i++)
			r[i]=cs[i];
	}
        if (date>n)return;//当date==n+1时r[i]还没有把cs[i]的都记录下来,要等记录完在return,所以放到下面
	cs[h+1]=date;
	dfs(Nans+c[date],date+1,m-a[date],v-b[date],h+1);
	dfs(Nans,date+1,m,v,h);
	return;
}
int main(){
	scanf("%d%d%d",&m,&v,&n);
	for (int i=1;i<=n;i++){
		scanf("%d%d%d",&a[i],&b[i],&c[i]);
	}
	dfs(0,1,m,v,0);
	printf("%d\n",ans);
	for(int i=1;i<=cho;i++)
		printf("%d ",r[i]);
	return 0;
}
posted @ 2021-10-05 20:12  hewt  阅读(81)  评论(0编辑  收藏  举报