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;
}
相关推荐
Blasit5 小时前
Qt C++ 编译 libevent静态库
开发语言·c++·qt
Aevget5 小时前
MFC扩展库BCGControlBar Pro v37.1——支持Visual Studio 2026
c++·mfc·bcg·界面控件·visual studio·ui开发
铅笔小新z5 小时前
【C++】 vector 全面解析:从使用到底层实现
开发语言·c++
傅里叶的耶5 小时前
C++ Primer Plus(第6版):第二章 开始学习C++
开发语言·c++·学习
雾岛听蓝5 小时前
C++ 类和对象(二):默认成员函数详解
开发语言·c++
郝学胜-神的一滴5 小时前
OpenGL中的glDrawArrays函数详解:从基础到实践
开发语言·c++·程序人生·算法·游戏程序·图形渲染
Trouvaille ~5 小时前
【LInux】进程程序替换与shell实现:从fork到exec的完整闭环
linux·运维·c语言·c++·ssh·进程替换·基础入门
YXWik65 小时前
Linux安装Whisper(C++版)音频解析文本
linux·c++·whisper
_OP_CHEN5 小时前
【从零开始的Qt开发指南】(十)Qt 常用控件之输入类控件全攻略:7 大控件从入门到实战,覆盖所有输入场景
开发语言·c++·qt·前端开发·qt常用控件·gui图形化界面·qt输入类控件