活跃农民
- 积分
- 441
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2013-3-14
- 最后登录
- 1970-1-1
|
POJ 1065: Wooden Sticks
题意比较复杂,不过概括一下就是给N个 pair <int, int>, 把pair分成x组使得每组里的pair第一个数和第二个数都是递增的, 求最小的组数(x值)
思路:这种的思路是首先按照第一维排序,然后就可以只考虑第二维的情况了。我们考虑贪心算法,假设 dp[ i ] 为到第i个pair为止的最长序列。那么是不是可以设 dp[ i ] = max{dp[j] + 1 | 0 <= j < i}呢?可惜这种做法是错误的,这里毕竟不是找最长上升子序列,而是找把数组分成若干个上升子序列的最小划分组数。一种正确的贪心策略是从第一个pair开始往后找,合并所有能合并的pair, 一轮完成后组数 +1, 最后直到所有 pair都处理完,这样时间复杂度是 O(n^2)
这题的神奇O(NlogN)做法要用到Dilworth定理。把一个数列划分为上升子序列的最小分法,等于这个数列最长(严格单调)下降子序列的长度。。反正我是没懂。。不过写了一下果然能 AC。。。
POJ 1631: Bridging signals
在位置i上有数字A[ i ]。左边的i号点在右边连上A[ i ]点,问最大的不相交边数
思路:这题看上去很吓人,但是稍微画一个例子立刻就能发现其实这题本质上就是求LIS.
POJ 2392: Space Elevator
n件物品,第i件hi高,有ci件,最高的一件不能超过ai的高度。问最高能堆多高
思路:有人在下面说了一句,差不多是裸的多重背包问题。一看果然如此。不过这题的关键在于我误会了ai的作用。最开始我以为是说每个物品不超过ai就行了,后来才发现ai是物品i能达到的最大高度。因此这里我们需要先对ai进行排序-首先处理那些最大高度限制比较小的物品,其他部分就和多重背包一模一样了。
POJ Making the Grade
给一列数A,问最小代价将其变成单调递增或者递减的。将数A[ i ]变成x的代价为 abs(A[ i ] - x)
思路:VMware最难的一套 OA 里面有这题。最开始一看就觉得稍微思索一下即可识破做法:我们用dp[ i ][j]来表示把前i个数变成non decreasing,同时把A[i-1]变成A[j]的最小cost。于是我们有:
dp[ i ][j] = abs(A[i-1]-A[j]) + min(dp[i-1][k] | 0 <= k <= j, A[k] <= A[j])
然后一提交 TLE ! 但是怎么想都觉得如果按照这个定义方法这个O(N^3)的复杂度是免不了的。后来偷喵了一眼题解才恍然大悟。这里之所以需要做第三层循环主要是因为A的排列不是递增的。但是我们可以新建另一个数组B,B是A的有序排列。用dp[ i ][j]来表示把前i个数变成non decreasing,同时把A[i-1]变成B[j]的最小cost。这样我们有:
dp[ i ][j] = abs(A[i-1] - b[j]) + min(dp[i-1][k] | 0 <= k <= j)
也就是说我们只需要记住 min(dp[i-1][0:j])的最小数即可,这个过程可以优化到O(1), 这样总的复杂度就是O(N^2)了。
POJ 2184: Cow Exhibition
N个 pair <ai, bi>, 求这些pair的总和sum(ai + bi) 最大值,但是限制 sum(ai), sum(bi) 都不得小于0
思路:这题能A真是有点喜出望外。让我们来看一看我最开始的错误思路。首先这个题目是稍微变化了一点的背包。我们可以定义 dp[ i ][j] 为前i个物品,ai的和为j的时候的最大总和。这么一来似乎我们就可以很简单的定义转移方程: dp[ i ][j] = max(dp[i-1][j], dp[i-1][j - a[i-1]]) 但是问题是这个必须大于等于0的限制怎么办呢?最开始我的想法是保证每个j都必须 >=0 以及 dp[ i ][j] - j (其实也就是 bi 的总和)必须 >=0。但是这么写出来发现不对!因为我们并不一定要求在每步转移的过程中 sum(ai) 都必须 >=0, 可能后面可以加上某 <ak, bk> 把sum(aj)加回正数。
既然这样,只好把这个限制条件去掉,也就是j可以<0, 最后求 max(dp[n][j] | j >= 0 and dp[n][j] - j >= 0) 即可。这里有个隐藏的细节,是否有可能某数 x 是满足条件的最大值,但是不在dp里因为 dp[n][j] > x 同时 dp[n][j] - j < 0 呢? 答案是不可能。反证法:如果 dp[n][j] > x 同时 dp[n][j] - j < 0,又因为x满足条件因此凑足x的bi总和必然 >=0, 既然如此 j + sum(bi) 必然 > dp[n][j], 和条件矛盾。
想通这点,下面的问题是 j < 0 的话坐标怎么办,我们可以简单的把所有j都加上W=100000, 也就是 ai 总和的最大值。初始化的时候要注意,dp[0][W] = 0, 代表前0个物品一个都不取,其他 dp[0][X] = -INF. 代表不可能前0个物品凑足 sum(ai) = X。最后返回 dp[N][j]的最大值即可(但是必须满足条件 j >= 0 而且 dp[N][j] >= 0)
要点:
1. 当需要求满足一定条件限制下的最优化问题的时候可以考虑背包
2. 不一定什么时候都能空间优化到1维数组,特别是在dp[ i ][j]同时依赖于dp[i-1][j-xx]和dp[i-1][j+xx]的时候,但是滚动数组是什么时候都能用的!
3. 如果状态有负数可以考虑将其index加到正数,出于写起来方便的角度,可以写完code以后统一加。
|
|