题解 P1910 【L国的战斗之间谍】
鄙人不才,最近狂写DP空间压缩的题解,不知道在想什么
1. 前言
二维动态规划题。
数据虽水,然该压还是得压 (说实话除了需要压缩空间之外就是大水题)。本文主要讲空间的压缩,针对对背包已有基础的童鞋,如不了解基本思路请参照其它
关于二维动规本人可能讲不太细,众
2. 关于题目思想
题目P1910主要内容为:有(低?) 于
3. 关于算法思想
可以看到,贪心是不可取的。虽然我不能具体说出为什么不可取
于是我们想到两条路子:搜索和动规。
搜索是一个并不好的算法,但是根据范围问题可以发现并不太可取 (当然可以尝试记忆化大法)。
尽管数据的奇异使搜索可能AC,但实际上不是所有数据都这么幸运。
我们考虑二维动规。
首先从一维角度来看(不考虑费用),这是
于是设
于是对于
现在加入(很乱有木有)。
则对于
上式根据
整理思路,首先二重循环输入数据存储于
参考代码如下:
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int a[105],b[105],c[105];
int f[105][1005][1005];
int main(){
int n,m,p;
cin>>n>>m>>p;
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i]>>c[i];
for(int i=1;i<=n;i++)
for(int j=m;j>=b[i];j--)
for(int k=p;k>=c[i];k--)
f[i][j][k]=max(f[i-1][j][k],f[i-1][j-b[i]][k-c[i]]+a[i]);
cout<<f[n][m][p];
return 0;
}
然而似乎非常不幸:
众看官是否发现了代码中的
于是自然可以想到压缩的问题:
3. a,b,c 压缩
这部分是本人的拿手压缩虽然常常无用,即输入部分的压缩。
首先让我们抛开
注意以下代码段:
for(int i=1;i<=n;i++)
cin>>a[i]>>b[i]>>c[i];
for(int i=1;i<=n;i++)
for(int j=m;j>=b[i];j--)
for(int k=p;k>=c[i];k--)
f[i][j][k]=max(f[i-1][j][k],f[i-1][j-b[i]][k-c[i]]+a[i]);
可以发现第二个循环部分每次都仅使用了
参考代码如下:
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int x,y,z;
int f[105][1005][1005];
int main(){
int n,m,p;
cin>>n>>m>>p;
for(int i=1;i<=n;i++){
cin>>x>>y>>z;
for(int j=m;j>=y;j--)
for(int k=p;k>=z;k--)
f[i][j][k]=max(f[i-1][j][k],f[i-1][j-y][k-z]+x);
}
cout<<f[n][m][p];
return 0;
}
4. f 数组压缩
动规的经典压缩方式(f压缩到二维)。
由上述内容可以看出,在计算第
这样看来,不妨直接使用方程
仔细观察方程,可发现每次 i 循环都更新了
其后第 i 层循环,实际上等同于使用
最后要注意一点,大部分这类压缩都要注意循环方向的问题,如此题状态转移需用到的数据为
当然本题本身是
整理思路,即是:将
参考代码如下:
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
int x,y,z;
int f[1005][1005];
int main(){
int n,m,p;
cin>>n>>m>>p;
for(int i=1;i<=n;i++){
cin>>x>>y>>z;
for(int j=m;j>=y;j--)
for(int k=p;k>=z;k--)
f[j][k]=max(f[j][k],f[j-y][k-z]+x);
}
cout<<f[m][p];
return 0;
}
5. 总结
越研究
感觉自己花式把一个简单的正解写得复杂之极……当然其中压缩的部分说不定还有些用处,毕竟
最后,感谢阅读完这175行的兄台。
以上。