比如经典的背包问题,每件物品有着选与不选两个决策,选的话就会导致状态的变化(更新)。
题目一:
https://www.luogu.org/problemnew/show/P1064
考虑主件,则每个主件有四种决策:不选,选一个主件,选一个主件加一个附件,选一个主件加两个附件,考虑每种决策可能对状态的更新就行了
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<bitset>
#include<vector>
using namespace std;
typedef long long ll;
typedef struct NODE{
int w,v;
}node;
vector<node>vt[65];
int dp[32005]={0};
int a[100];
int main()
{ int n,m;
cin>>n>>m;
int tot=0;
for(int i=1;i<=m;i++)
{
int w,v,x;
cin>>w>>v>>x;
if(x==0)
{
a[tot++]=i;
vt[x].push_back((node){w,v});
}
else vt[x].push_back((node){w,v});
}
for(int i=0;i<tot;i++)
{
for(int j=n;j>=0;j--)
{
if(j>=vt[0][i].w)
{
dp[j]=max(dp[j],dp[j-vt[0][i].w]+vt[0][i].w*vt[0][i].v);
}
int l=vt[a[i]].size();
if(l==2&&j>=vt[0][i].w+vt[a[i]][0].w+vt[a[i]][1].w)
{
int t=dp[j-(vt[0][i].w+vt[a[i]][0].w+vt[a[i]][1].w)];
t+=vt[0][i].w*vt[0][i].v+vt[a[i]][0].w*vt[a[i]][0].v+vt[a[i]][1].w*vt[a[i]][1].v;
dp[j]=max(dp[j],t);
}
while(l--)
{ if(j>=vt[0][i].w+vt[a[i]][l].w)
{
int t=dp[j-vt[0][i].w-vt[a[i]][l].w]+vt[0][i].w*vt[0][i].v+vt[a[i]][l].w*vt[a[i]][l].v;
dp[j]=max(dp[j],t);
}
}
}
}
cout<<dp[n]<<endl;
return 0;
}
题目二:
https://www.luogu.org/problemnew/show/P1280
在同一时刻,有多个方案的话,就会存在最优决策问题,而你发现不管选哪个,前面时间段最优肯定是不会变的,这种像是没有“前效性”,而不同的选择会到达之后不同的时间点,就是以时间点为状态的逆推DP(或记忆化搜索)
#include<iostream>
#include<vector>
using namespace std;
struct NODE{
int l,r;
}e[10005];
int dp[10005];
vector<int>vt[10005];
int main()
{
int n,k;
cin>>n>>k;
for(int i=1;i<=k;i++)
{
scanf("%d%d",&e[i].l,&e[i].r);
vt[e[i].l].push_back(i);
}
dp[n+1]=0;
for(int i=n;i>=1;i--)
{ int l=vt[i].size();
if(l==0) dp[i]=dp[i+1]+1;
else
{ dp[i]=0;
for(int k=0;k<l;k++)
{
dp[i]=max(dp[i],dp[i+e[vt[i][k]].r]);
}
}
}
cout<<dp[1]<<endl;
return 0;
}
题目三:
https://www.luogu.org/problemnew/show/P1417
说到决策,就不难想到贪心,这个题就是贪心+01背包
因为这题在不同的时间点或者说先做或后做某件事,产生的贡献是不一样,这就和背包不一样
假设两个物品x,y
先x:a[x]-(p+c[x])*b[x]+a[y]-(p+c[x]+c[y])*by
先y:a[y]-(p+c[y])*b[y]+a[x]-(p+c[y]+c[x])*bx
可知:c[x]*b[y]<c[y]*b[x].时,先选x是优于先选y的。
所以,先排序,后01背包
#include<iostream>
#include<vector>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
ll dp[100005];
struct NODE{
ll a,b,c;
}e[200];
bool cmp(struct NODE x,struct NODE y)
{
return x.c*y.b<x.b*y.c;
}
int main()
{ int T,n;
cin>>T>>n;
for(int i=1;i<=n;i++)
{
scanf("%lld",&e[i].a);
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&e[i].b);
}
for(int i=1;i<=n;i++)
{
scanf("%lld",&e[i].c);
}
sort(e+1,e+1+n,cmp);
memset(dp,-1,sizeof dp);
dp[0]=0;
for(ll i=1;i<=n;i++)
{
for(ll j=T;j>=0;j--)
{
if (dp[j] != -1 && j + e[i].c <= T)
dp[j + e[i].c] = max(dp[j + e[i].c], dp[j] + e[i].a - (j + e[i].c) * e[i].b);
}
}
ll mx=0;
for(int i=0;i<=T;i++)
mx=max(dp[i],mx);
cout<<mx<<endl;
return 0;
}