ACM学习历程—UESTC 1218 Pick The Sticks(动态规划)(2015CCPC D)

题目链接: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背包应该从lena[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;
}
View Code

 

posted on 2015-11-28 13:40  AndyQsmart  阅读(247)  评论(0编辑  收藏  举报

导航