20251210 DP小测总结

杨老师讲到C题的时候全班都望着我。

A P1233 木棍加工

首先用结构体把数据接进来,然后把宽度作为第一关键字降序排序,把长度作为第二关键字升序排序,接下来就是求所有木棍的长度最少可以由几个不上升子序列组成,也就是求最长上升子序列的长度。

死因:初始化dp[1]=1,其余为0。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
	int l,w;
}a[5005];
bool cmp(node x,node y){
    if(x.w==y.w){
        return x.l>y.l;
    }
	return x.w>y.w;
}
int dp[5005];
int main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>a[i].l>>a[i].w;
	}
	sort(a+1,a+1+n,cmp);
	int mx=1;
	for(int i=1;i<=n;i++){
        dp[i]=1;
		for(int j=1;j<i;j++){
			if(a[j].l<a[i].l){
				dp[i]=max(dp[i],dp[j]+1);
			}
		}
		mx=max(mx,dp[i]);
	}
	cout<<mx;
	return 0;
} 

B P1336 最佳课题选择

01背包,就是要多循环一次,枚举第 i 种作文写 l(是 l 还是大写 i 呢) 篇,重量为 l,价值为a[i]*pow(i,b[i])

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
long long a[205],b[205],dp[205];
long long check(long long x,long long y){
	long long uns=1;
	while(y--){
		uns*=x;
	}
	return uns;
}
int main(){
	memset(dp,0x3f,sizeof dp);
	dp[0]=0;
	long long n,m;
	cin>>n>>m;
	for(long long i=1;i<=m;i++){
		cin>>a[i]>>b[i];
	}
	for(long long i=1;i<=m;i++){
		for(long long j=n;j>=1;j--){
			for(long long l=1;l<=j;l++){
				dp[j]=min(dp[j],dp[j-l]+a[i]*check(l,b[i]));
			}
		}
	}
	cout<<dp[n];
	return 0;
}

C P1103 书本整理

首先明确题意:需要从n本书中移除k本,即保留n-k本。

我们定义数组f[i][j],表示在前i本书中选择j本保留(其中必须包含第i本)时的最小不整齐度。

状态转移方程推导如下:

由于第i本必须保留,因此前i-1本书中需要保留j-1本。设从j-1到i之间保留的书为p,可得:

dp[i][j]=min(dp[i][j],dp[p][j-1]+abs(a[i].w-a[p].w));

下面看具体的代码实现:

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
struct node{
	int h,w;
}a[105];
bool cmp(node x,node y){
	return x.h<y.h;
}
int dp[205][205];
int main(){
	memset(dp,0x3f,sizeof dp);
	int n,k;
	cin>>n>>k;
	for(int i=1;i<=n;i++){
		cin>>a[i].h>>a[i].w;
		dp[i][0]=dp[i][1]=0;
	}
	sort(a+1,a+1+n,cmp);
	for(int i=1;i<=n;i++){
		for(int j=1;j<=min(i,n-k);j++){
			for(int p=0;p<i;p++){
				dp[i][j]=min(dp[i][j],dp[p][j-1]+abs(a[i].w-a[p].w));
			}
		}
	}
	int ans=INT_MAX;
	for(int i=n-k;i<=n;i++){
		ans=min(ans,dp[i][n-k]);
	}
	cout<<ans;
	return 0;
}

D B3873 [GESP202309 六级] 小杨买饮料

我们先用01背包的模板计算在重量限制为 i 时能获得的最大价值,其中 i 的最大值为所有物品重量之和。然后从0开始遍历,如果发现某个重量i对应的价值超过L,就立即输出 i 并终止程序。

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int c[505],l[505],dp[4000005];
int main(){
	memset(dp,0x3f,sizeof dp);
	dp[0]=0;
	int n,L,sum=0;
	cin>>n>>L;
    for(int i=1;i<=n;i++){
        cin>>c[i]>>l[i];
        if(l[i]>L){
			l[i]=L;
		}
        sum+=l[i];
        for(int j=sum;j>=l[i];j--){
            dp[j]=min(dp[j],dp[j-l[i]]+c[i]);
        }
    }
    if(sum<L){
        cout<<"no solution";
        return 0;
    }
    int mn=INT_MAX;
    for(int i=sum;i>=L;i--){
		mn=min(mn,dp[i]);
	}
	cout<<mn;
	return 0;
}

E P8742 [蓝桥杯 2021 省 AB] 砝码称重

为什么我会错呢?

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int a[105],dp[100005];
int main(){
	dp[0]=1;//0重量无需任何代价
	int n,sum=0;
	cin>>sum;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		sum+=a[i];//总重量
	}
	for(int i=1;i<=n;i++){//枚举物品
		for(int j=sum;j>=1;j--){//枚举容量
			if(dp[j+a[i]]||dp[abs(j-a[i])]){//是放在左边还是放在右边?
				dp[j]=1;
			}
		}
	}
	int ans=0;
	for(int j=1;j<=sum;j++){//0不算,阴不阴?
		if(dp[j]==1)ans++;//如果可以称出这种重量
	}
	cout<<ans;
	return 0;
}
相关推荐
王老师青少年编程6 小时前
csp信奥赛C++高频考点专项训练之贪心算法 --【哈夫曼贪心】:合并果子
c++·算法·贪心·csp·信奥赛·哈夫曼贪心·合并果子
叼烟扛炮7 小时前
C++第二讲:类和对象(上)
数据结构·c++·算法·类和对象·struct·实例化
样例过了就是过了8 小时前
LeetCode热题100 最长公共子序列
c++·算法·leetcode·动态规划
谭欣辰9 小时前
C++ 排列组合完整指南
开发语言·c++·算法
橙子也要努力变强9 小时前
信号捕捉底层机制-机理篇2
linux·服务器·c++
盐焗鹌鹑蛋10 小时前
【C++】stack和queue类
c++
郝学胜-神的一滴11 小时前
罗德里格斯旋转公式(Rodrigues‘ Rotation Formula)完整推导
c++·unity·godot·图形渲染·three.js·unreal
lzh2004091911 小时前
深入理解进程:从PCB内核结构到写时拷贝的底层实战
linux·c++
aseity11 小时前
跨平台项目中QString 与 非Qt 跨平台动态库在字符集上的一个实用的互操作约定.
c++·经验分享
CN-Dust11 小时前
【C++】while语句例题专题
数据结构·c++·算法