标签:
题目链接:http://acm.uestc.edu.cn/#/problem/show/1218
题目大意就是求n根木棒能不能放进一个容器里,乍一看像01背包,但是容器的两端可以溢出容器,只要两端的木棒的重心还在容器中即可。
首先由于木棒可以两端溢出、一端溢出和不溢出三种情况,所以有状态p(flag, v)表示溢出个数为flag的容量为v的情况下的最值。
于是有:
p[2][j] = max(p[2][j], p[2][j-a[i]]+v[i]);
p[2][j] = max(p[2][j], p[1][j-a[i]/2]+v[i]);
p[1][j] = max(p[1][j], p[1][j-a[i]]+v[i]);
p[1][j] = max(p[1][j], p[0][j-a[i]/2]+v[i]);
p[0][j] = max(p[0][j], p[0][j-a[i]]+v[i]);
然后处理j那一维类似于01背包应该从len到a[i]/2,然后对j<a[i]的情况特判。
不过到这里,还没结束,应该a[i]/2不一定是整除。
所以可以先对所有的a[i]和len乘上2,然后再进行运算。。。
代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <algorithm> #include <set> #include <map> #include <queue> #include <string> #define LL long long using namespace std; const int maxN = 1005; int n, len; int a[maxN], v[maxN]; LL p[4][maxN<<2]; void input() { scanf("%d%d", &n, &len); len <<= 1; for (int i = 0; i < n; ++i) { scanf("%d%d", &a[i], &v[i]); a[i] <<= 1; } memset(p, 0, sizeof(p)); } void work() { if (n == 1) { cout << v[0] << endl; return; } for (int i = 0; i < n; ++i) { for (int j = len; j >= a[i]/2; --j) { if (j-a[i] >= 0) p[2][j] = max(p[2][j], p[2][j-a[i]]+v[i]); p[2][j] = max(p[2][j], p[1][j-a[i]/2]+v[i]); if (j-a[i] >= 0) p[1][j] = max(p[1][j], p[1][j-a[i]]+v[i]); p[1][j] = max(p[1][j], p[0][j-a[i]/2]+v[i]); if (j-a[i] >= 0) p[0][j] = max(p[0][j], p[0][j-a[i]]+v[i]); } } cout << p[2][len] << endl; } int main() { //freopen("test.in", "r", stdin); int T; scanf("%d", &T); for (int times = 1; times <= T; ++times) { printf("Case #%d: ", times); input(); work(); } return 0; }
ACM学习历程—UESTC 1218 Pick The Sticks(动态规划)(2015CCPC D)
标签:
原文地址:http://www.cnblogs.com/andyqsmart/p/5002575.html