从AOJ的塔,到POJ的ferry loading,ferry loading到浙江省赛的第7题Process the Tasks,发现这三个问题都是一类比较典型的dp,有必要好好总结一下,避免以后再出现就不会了
这类题目比较原始的版本是
AOJ的塔问题(题目链接)
题意:给你一堆积木,选择其中的某些来组成两个相同高度的塔(对于某块积木,可以放在塔1,可以放在塔2,也可以都不放),问你最大组成的高度是多少?
解析:这个题目不太容易想,我是请教cxlove的(自己太水了),比较常规的想法是用两维表示塔1和塔2的高度,可是这样必然MLE,我们得选取另一个状态来进行DP,这个状态就是两个塔的高度差,dp【i】【j】表示前i个积木用于搭建了两座塔,相差高度为j的时候,两塔的最大高度和。
dp【i+1】【j+block【i+1】】=max(dp【i+1】【j+block【i+1】】,dp【i】【j】+block【i+1】);这个表示i+1块积木放在较高的塔上
dp【i+1】【j-block【i+1】】=max(dp【i+1】【j-block【i+1】】,dp【i】【j】+block【i+1】);这个表示i+1块积木放在较低的塔上
题目数据比较大,必须得用到滚动数组,而且还得继续优化,不然TLE,经过优化,可以达到300ms+。
详细代码见下方。
另一个差不多的题目是poj 2609 ferry loading(题目链接)
题意:给你两个相同车库,每个车库能装M长度的车子,现在给你一个车队(不能改变车队序列的顺序),每辆车子的长度,问你最多能装入多少辆汽车,输出路径
解析:这个题目和上一个题目差不多,不过这里还多了个限制,就是不能总长度超过M*2。
此题,个人能力有限。。没有弄出来输出路径,所以丑陋的代码就不贴了
还有一个题目,就是zoj 3331 浙江省赛的题目(题目链接)
题意:一个加工厂里面有两个机器人,然后有一堆货物需要加工,这些货物加工必须按照顺序来,第n件物品能进行加工的前提条件是n-1件物品加工完成或正在加工。
解析:这个题目相对上面两个题目复杂一点,但还是差不多,dp【i】【j】表示前i件物品加工完了(或i-1件正在加工中)的时候,j表示两个机器人的工作时间差距,dp表示最少耗费的时间。
其中j>0表示a机器人的工作时间更长,j<0表示b机器人工作时间更长
(更新)POJ 1015 (题目链接)
脑子转不过来,数据范围估算错误,不过学习了不少东西
题意:在n个数中选择K个数,使其和的绝对值最小。
解析:因为绝对值范围有限,所以直接开一维表示绝对值,其余的差不多。
状态转移方程比较麻烦,我直接在代码里面附上注释好了,详情见代码
/* aoj 518 塔*/
#include
#include
#include
#define INF 1<<29
int dp[2][500010];
int a[51],sum[51];
int cmp(const void *a,const void *b)
{
return *(int *)a-*(int *)b;
}
int main()
{
int n,i,j;
int t;
while(scanf("%d",&n)!=EOF)
{
for(i=1;i<=n;i++)
scanf("%d",&a[i]);
qsort(&a[1],n,sizeof(a[0]),cmp);
sum[1]=a[1];
for(i=2;i<=n;i++)
sum[i]=sum[i-1]+a[i];//提前算出高度差,然后枚举高度差的时候就不用编立500000了
for(i=0;i<=sum[n];i++)
dp[0][i]=-INF;
dp[0][0]=0;
for(i=0;i
/*zoj 3331 */
#include
#include
#define offset 100
#define INF 1<<25
#define min(a,b) ((a)<(b)?(a):(b))
#define get(a) ((a)<0?0:(a))
using namespace std;
const int maxn=105;
int dp[maxn][maxn*2];
int costa[maxn],costb[maxn];
int n,m;
int main()
{
int i,j,k,T;
cin>>T;
while(T--)
{
cin>>n;
for(i=1;i<=n;i++)
cin>>costa[i]>>costb[i];
for(i=0;i<=n;i++)
for(j=0;j<210;j++)
dp[i][j]=INF;
dp[0][0+offset]=0;
for(i=0;i