
杨老师讲到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;
}