https://www.luogu.com.cn/problem/P1060
P1060 [NOIP2006 普及组] 开心的金明
一道典型的背包问题
思路:先说二维的dp[i][j],i表示0---i件物品是花费j元的情况,也就是说先从第一层(i=1)的情况都更新,然后再更新(i=2)的情况,i=2的情况是在i=1的情况下推倒出来的,因此我们就可以得到
一维转移方程:f[j]=max(f[j],f[j-v[i]]+v[i]*w[i])
dfs:思路,选或者不选,每个都枚举一遍,要注意最后意见物品的选择(如果我们选择最后一件物品,那么number会出现number>m的情况,因此我们要在判断位置之前要更新我们的答案)以及花钱的边界。
dfs:
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll value[3000005],spend[3000005],n,m;
int ans=0;
void dfs(int number,int money,int jiazhi)
{
if(money>0)ans=max(jiazhi,ans);
if(number>m)return;
dfs(number+1,money-spend[number],jiazhi+value[number]);//选
dfs(number+1,money,jiazhi);//不选
}
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>spend[i]>>value[i];
value[i]=spend[i]*value[i];
}
dfs(1,n,0);
cout<<ans<<endl;
return 0;
}
二维代码:转移方程 dp[i][j]=max(dp[i-1][j],dp[i-1][j-spen[i]]+value[i]);
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll dp[30][3000005],n,m,ans,value[3000005],spend[30000005];
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>spend[i]>>value[i];
value[i]=spend[i]*value[i];
}
for(int i=1;i<=m;i++)
{
for(int j=1;j<=n;j++)
{
if(j>=spend[i])
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-spend[i]]+value[i]);
}
else dp[i][j]=dp[i-1][j];
}
}
cout<<dp[m][n]<<endl;
return 0;
}
一维代码:一维转移方程:f[j]=max(f[j],f[j-v[i]]+v[i]*w[i])
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll dp[3000005],n,m,ans,value[3000005],spend[30000005];
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>spend[i]>>value[i];
value[i]=spend[i]*value[i];
}
for(int i=1;i<=m;i++)
{
for(int j=n;j>=spend[i];j--)
{
dp[j]=max(dp[j],dp[j-spend[i]]+value[i]);
}
}
cout<<dp[n]<<endl;
return 0;
}
https://www.luogu.com.cn/problem/P1164
P1164 小A点菜
dfs:普通的dfs的时间复杂度是:2^100,显然如果都枚举完会超时,那么我们就需要通过剪枝来优化我们的复杂度,就能过了。
dfs+剪枝代码:
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll ans=0,n,m,spend[1005],dp[105][100005];
ll dfs(int i,int m)
{
if(i>n||m<0)return 0;//边界
if(dp[i][m])return dp[i][m];//剪枝
if(m==spend[i])dp[i][m]+=1;//如果剩余的钱刚好够钱点第i个那么我们就让总的方案书+1
dp[i][m]+=dfs(i+1,m-spend[i]);//点第i个套餐
dp[i][m]+=dfs(i+1,m);//不点第i个套餐
//总方案数=点第i个套餐的方案+不点第i个套餐的方案,i从1开始,因此前面每个i的情况都枚举完了。
return dp[i][m];
}
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>spend[i];
dp[n][m]=dfs(1,m);
cout<<dp[n][m];
return 0;
}
二维dp:转移方程:if(j>=spend[i]) dp[i][j]=dp[i-1][j]+dp[i-1][j-spend[i]];
else dp[i][j]=dp[i-1][j];
代码:
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll dp[105][10005],n,m,spend[10005];
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>spend[i];
for(int i=0;i<=n;i++)dp[i][0]=1;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=m;j++)
{
if(j<spend[i])dp[i][j]=dp[i-1][j];
else dp[i][j]=dp[i-1][j]+dp[i-1][j-spend[i]];
}
}
cout<<dp[n][m]<<endl;
return 0;
}
一维:dp[0]=1, dp[j]=dp[j]+dp[j-value[i]];
一维代码:
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll dp[10005],n,m,spend[10005];
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n>>m;
for(int i=1;i<=n;i++)cin>>spend[i];
dp[0]=1;
for(int i=1;i<=n;i++)
{
for(int j=m;j>=spend[i];j--)
{
dp[j]=dp[j]+dp[j-spend[i]];
}
}
cout<<dp[m]<<endl;
return 0;
}
https://www.luogu.com.cn/problem/P1115
P1115 最大子段和
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
int f[211111],n;
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
int x;
cin>>x;
f[i]=max(f[i-1]+x,x);//dp
}
int maxx=-999999;
for(int i=1;i<=n;i++)
{
maxx=max(f[i],maxx);
}
cout<<maxx<<endl;
return 0;
}
https://www.luogu.com.cn/problem/P1734
P1734 最大约数和
dp题
一维转移方程:dp[j]=max{dp[j],dp[j-i]+yue[i]};
如果用二维来写,那么需要注意的是在第二个循环里,我们必须对每一个数都更新,因为在下一层状态可能需要到本层的状态,这里我被卡了好久...
二维转移方程:if(j<i)dp[i][j]=dp[i-1][j];
else dp[i][j]=max{dp[i-1][j],dp[i-1][j-i]+yue[i]};
一维代码:
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
int yueshu[1005],dp[1005],n;
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
int temp=0;
for(int j=1;j<=i/2;j++)
{
if(i%j==0)
{
temp+=j;
}
}
yueshu[i]=temp;
}
for(int i=1;i<=n;i++)
{
for(int j=n;j>=i;j--)
{
dp[j]=max(dp[j],dp[j-i]+yueshu[i]);
}
}
cout<<dp[n]<<endl;
return 0;
}
二维代码:
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
int yueshu[1005],dp[1005][1005],n;
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++)
{
int temp=0;
for(int j=1;j<=i/2;j++)
{
if(i%j==0)
{
temp+=j;
}
}
yueshu[i]=temp;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if(j<i)dp[i][j]=dp[i-1][j];
else dp[i][j]=max(dp[i-1][j],dp[i-1][j-i]+yueshu[i]);
}
}
cout<<dp[n][n];
return 0;
}
https://www.luogu.com.cn/problem/P1002
P1002 [NOIP2002 普及组] 过河卒
画图,转移方程:dp[i][j]=max(d[i][j],dp[i-1][j]+dp[i][j-1]);
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll dp[25][25],pd[25][25],mx,my,zx,zy;
int dx[]={0,1,1,-1,-1,-2,-2,2,2};
int dy[]={0,2,-2,2,-2,1,-1,1,-1};
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>zx>>zy>>mx>>my;
zx=zx+2;zy=zy+2;mx=mx+2;my=my+2;
for(int i=0;i<=8;i++)
{
int xx=mx+dx[i];
int yy=my+dy[i];
pd[xx][yy]=1;
}
dp[2][2]=1;
for(int i=2;i<=zx;i++)
{
for(int j=2;j<=zy;j++)
{
if(pd[i][j])continue;
else dp[i][j]=max(dp[i][j],dp[i-1][j]+dp[i][j-1]);
}
}
cout<<dp[zx][zy]<<endl;
return 0;
}
https://www.luogu.com.cn/problem/P1616
P1616 疯狂的采药
转移方程:dp[j]=max(dp[j],dp[j-spend[i]]+value[i]);
答案=max(选择,不选择);
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll value[20000005],spend[20000005],dp[20000005],n,t;
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>t>>n;
for(int i=1;i<=n;i++)
{
cin>>spend[i]>>value[i];
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=t;j++)
{
if(j>=spend[i])dp[j]=max(dp[j],dp[j-spend[i]]+value[i]);
}
}
cout<<dp[t];
return 0;
}
https://www.luogu.com.cn/problem/P1048
P1048 [NOIP2005 普及组] 采药
转移方程:dp[j]=max(dp[j],dp[j-spend[i]+value[i]);
#include<bits/stdc++.h>
#define ll long long
#define rep(a,b,c) for(int a=b;a<=c;a++)
#define per(a,b,c) for(int a=b;a>=c;a--)
#define hh 0x3f3f3f3f
using namespace std;
inline int read()
{
ll s=0,f=1;
char c=getchar();
while(c>'9'||c<'0'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){s=(s<<3)+(s<<1)+c-'0';c=getchar();}
return s*f;
}
ll dp[100000],n,t,value[100000],spend[100000];
int main()
{
ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
cin>>t>>n;
for(int i=1;i<=n;i++)cin>>spend[i]>>value[i];
for(int i=1;i<=n;i++)
{
for(int j=t;j>=spend[i];j--)
{
dp[j]=max(dp[j],dp[j-spend[i]]+value[i]);
}
}
cout<<dp[t];
return 0;
}