题意:给定一些物品放置在承重为S的桌子上, 每个物品有5个属性,放置时间in,拿开时间out,重量w,承重s及放置后的收益v。而且后面放置上去的必须先拿开。。求一种合法的放置使得收益最大,输出收益。
思路:先对所有的物品按照out递增,out相同l递减的情况排序。
那么很容易想到dp。。
f[i][j]表示放置了第i个,还可承重j的最大收益(i本身还没算)。
把(in[i], out[i])看成线段
那么,等价于(in[i], out[i])之间找出最多不相交线段。
这个可以用记忆化搜索,当然也可以非递归。。
具体看代码应该比较容易懂吧。。
code:
1 #include <bits/stdc++.h> 2 using namespace std; 3 struct oo{ 4 int l, r, w, s, v; 5 void input(){ 6 scanf("%d%d%d%d%d", &l, &r, &w, &s, &v); 7 } 8 bool operator<(const oo& p) const{ 9 return r < p.r || (r == p.r && l > p.l); 10 } 11 } a[512]; 12 int n, s, f[512][1024], tmp[1024]; 13 void solve(){ 14 a[0] = (oo){0, n*2, 0, s, 0}; 15 for (int i = 1; i <= n; ++i) a[i].input(); 16 sort(a, a + n + 1); 17 int cur, s1; 18 for (int i = 0; i <= n; ++i) 19 for (int j = a[i].w; j <= s; ++j){ 20 tmp[cur = a[i].l] = 0; 21 s1 = min(j-a[i].w, a[i].s); 22 for (int k = 0; k < i; ++k) if (a[k].l >= a[i].l){ 23 for (;cur<a[k].r;) 24 ++cur, tmp[cur] = tmp[cur-1]; 25 tmp[cur] = max(tmp[cur], tmp[a[k].l] + f[k][s1]); 26 } 27 f[i][j] = tmp[cur] + a[i].v; 28 } 29 cout << f[n][s] << endl; 30 } 31 32 int main(){ 33 // freopen("a.in", "r", stdin); 34 while (scanf("%d%d", &n, &s) != EOF){ 35 solve(); 36 } 37 }