目录
4549. 做作业 - 状态dp
这题对我来说很难,写个题解理解一下,拓展做题思路+提高理解能力
题目:
思路:
f[i]完成作业状态为i的最小扣分
详见代码注释部分
#include <iostream>
#include <algorithm>
#include <cstring>
#include <stack>
using namespace std;
const int N=16;
int n;
struct node
{
string lesson;
int ddl,t;
}a[N];
int f[1<<N]; //f[i]完成作业状态为i的最小扣分
int tt[1<<N];
int ans[1<<N];
void solve()
{
cin>>n;
for(int i=0;i<n;i++) cin>>a[i].lesson>>a[i].ddl>>a[i].t;
memset(f,0x3f,sizeof f);
memset(ans,0,sizeof ans);
memset(tt,0,sizeof tt);
for(int i=0;i<1<<n;i++) //枚举所有可能的完成作业状态 比如110表示第一科没完成 第二科和第三科完成
for(int j=0;j<n;j++)
if(i>>j&1) tt[i]+=a[j].t; //预处理每一种状态花费的总时间
f[0]=0;
for(int i=0;i<1<<n;i++)
for(int j=0;j<n;j++)
if(!(i>>j&1)) //如果这一科未完成(该位为0)
{
int pre=i; //记录未改变时状态
int now=i+(1<<j); //将这一科完成(该位变为1)
int score=max(0,tt[pre]+a[j].t-a[j].ddl);
//扣分数=之前的总费时+当前这科的完成时间-当前这科的完成时限
//注意扣的分数不能为负数
if(f[now]>f[pre]+score) //更新最小扣分数
{
f[now]=f[pre]+score;
ans[now]=pre; //ans记录前驱(now状态由pre状态转化过来)
}
}
cout<<f[(1<<n)-1]<<endl; //答案即为f[n科均完成的状态]
int ed=(1<<n)-1;
stack<string> stk;
while(ed) //从最后的状态倒推至初始状态000
{
int x=0;
int pre=ans[ed];
for(int i=0;i<n;i++)
if((ed>>i&1)&&!(pre>>i&1)) //如果该位改变(之前是0 现在是1)
{
x=i;
break;
}
stk.push(a[x].lesson);
//因为ans记录的是更新转移过来的状态
//所以
ed=pre;
}
while(!stk.empty()) cout<<stk.top()<<endl,stk.pop();
}
int main()
{
int t;
cin>>t;
while(t--)
{
solve();
}
}
4550. 超级跳跳跳 - 最长上升子序列dp
题目:
思路:
根据题目要求分析,就是求最长上升子序列的最大值
import java.util.*;
class Main
{
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
while(true)
{
int n=sc.nextInt();
if(n==0) break;
int[] f=new int[n+1],a=new int[n+1];
for(int i=1;i<=n;i++) a[i]=sc.nextInt();
int res=-1;
for(int i=1;i<=n;i++)
{
f[i]=a[i];
for(int j=1;j<i;j++)
if(a[j]<a[i]) f[i]=Math.max(f[i],f[j]+a[i]);
res=Math.max(res,f[i]);
}
System.out.println(res);
}
}
}
4551. 猪猪存钱罐 - 完全背包问题
题目:
已知钱币的总重量,和每种硬币单个重量及面额
求恰好凑出总重量的最小面额总值
若无法恰好凑出,输出This is impossible.
思路:
每种货币无限件 + 存钱罐重量有限制 = 完全背包模板
定义f[i]:总重量为i的最小总价值
套完全背包模板即可,注意初始化时f数组全为正无穷
且f[0]=0(重量为0的价值为0)
完全背包等各类背包问题:【蓝桥杯集训25】背包DP(5 / 7)_Roye_ack的博客-CSDN博客
如果f[v]不是正无穷,说明刚好装满的状态可达,否则无法恰好装满
1、c++
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=10010;
int f[N];
int main()
{
int t;
cin>>t;
while(t--)
{
int a,b;
cin>>a>>b;
int V=b-a;
memset(f,0x3f,sizeof f);
int n;
cin>>n;
f[0]=0;
for(int i=1;i<=n;i++)
{
int w,v;
cin>>w>>v;
for(int j=v;j<=V;j++)
f[j]=min(f[j],f[j-v]+w);
}
if(f[V]!=0x3f3f3f3f) cout<<"The minimum amount of money in the piggy-bank is "<<f[V]<<"."<<endl;
else cout<<"This is impossible."<<endl;
}
}
2、java 这版vjudge格式被卡 acw可以过
import java.util.*;
class Main
{
static int N=10010;
static int[] f=new int[N];//f[i]总重量不超过i的最小总价值
//每种物品无限件+有体积限制=完全背包问题
public static void main(String[] args)
{
Scanner sc=new Scanner(System.in);
int t=sc.nextInt();
while(t-->0)
{
int a=sc.nextInt(),b=sc.nextInt();
int V=b-a;
int n=sc.nextInt();
Arrays.fill(f,0x3f3f3f3f);
f[0]=0; //重量为0的价值为0
for(int i=1;i<=n;i++)
{
int w=sc.nextInt(),v=sc.nextInt();
for(int j=v;j<=V;j++)
f[j]=Math.min(f[j],f[j-v]+w);
}
if(f[V]!=0x3f3f3f3f) System.out.printf("The minimum amount of money in the piggy-bank is %d.\n",f[V]);
else System.out.println("This is impossible.");
}
}
}