一、01背包:P1048 [NOIP2005 普及组] 采药
f[i] 表示在 i 时间内所能采到的最大药草,容易得到 f[i]=max(f[i],f[i-w[i]]+v[i]) 。
然而存在重复采同一株药的情况,于是设计新的状态 f[i][j] 表示在前 i 株药草中,时间为 j 所能采到的最多的药草。
由此推出新的转移方程:f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+v[i]) 。意思也就很好理解( 然而我花了很久才理解 qwq )。
状态由前 i-1 株药草时间为 j-w[i] 的状态推过来,再取一个 max 就好了。(前提是 j 大于 w[i] )下面放代码:
1 #include<iostream> 2 #define N 101 3 using namespace std; 4 int t,n,w[N],v[N],f[N][N*10]; 5 int main() 6 { 7 cin>>t>>n; 8 for(int i=1;i<=n;i++) 9 cin>>w[i]>>v[i]; 10 for(int i=1;i<=n;i++) 11 for(int j=1;j<=t;j++) 12 { 13 f[i][j]=f[i-1][j]; 14 if(j<w[i]) continue; 15 f[i][j]=max(f[i-1][j-w[i]]+v[i],f[i][j]); 16 } 17 cout<<f[n][t]<<'\n'; 18 return 0; 19 }
这是二位数组写法。但我们发现求 f[i][j] 时只会用到 f[i-1][j] 的数据,所以可以优化一维。代码如下:
1 #include<iostream> 2 using namespace std; 3 int t,n,w[101],v[101],f[1010]; 4 int main() 5 { 6 cin>>t>>n; 7 for(int i=1;i<=n;i++) 8 cin>>w[i]>>v[i]; 9 for(int i=1;i<=n;i++) 10 for(int j=t;j>=w[i];j--) 11 f[j]=max(f[j-w[i]]+v[i],f[j]); 12 cout<<f[t]<<'\n'; 13 return 0; 14 }
二、完全背包
上面代码真的短,但是要注意, j 是倒序枚举,防止一株药被采多次。那完全背包正序枚举不就行了吗?没错,就是这样!代码如下:(P1616 疯狂的采药)
1 #include<iostream> 2 using namespace std; 3 int w[10010],v[10010]; 4 long long t,n,f[10000010]; 5 int main() 6 { 7 cin>>t>>n; 8 for(int i=1;i<=n;i++) 9 cin>>w[i]>>v[i]; 10 for(int i=1;i<=n;i++) 11 for(int j=w[i];j<=t;j++) 12 f[j]=max(f[j-w[i]]+v[i],f[j]); 13 cout<<f[t]<<'\n'; 14 return 0; 15 }
三、写题心得:
背包直到前几天才真正理解了一点,又因为树链剖分耽搁了一下,所以今天才来写这个博客( 还是用的信息课 qwq )。现在终于写完了——刚好下课!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探