HDU4341 Gold miner 分组背包

这里有多个点与原点的连线共线的话,那么需要对其进行并组,将前一个作为单独的一个,把前两个作为单独的一个...最后直接分组背包就可以了。

代码如下:

#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 205
using namespace std;

int N, M, cnt[MAXN], vis[MAXN], idx;

int f[40005];

struct Node
{
    int x, y, t, v;
    bool operator < (Node temp) const
    {
        return y < temp.y;
    } // 对y轴进行排序,这样保证能够先得到最近的点 
}e[MAXN];

struct Team
{
    int t, v;
}p[MAXN][MAXN];

bool Inline(int a, int b)
{
    return e[a].x * e[b].y == e[a].y * e[b].x;
}

void init()
{
    int st = 0, sv = 0;
    idx = 0;
    memset(vis, 0, sizeof (vis));
    memset(cnt, 0, sizeof (cnt));
    for (int i = 1; i <= N; ++i) {
        if (!vis[i]) {
            vis[i] = 1;
            ++idx, ++cnt[idx];
            st = e[i].t, sv = e[i].v;
            p[idx][cnt[idx]].t = st;
            p[idx][cnt[idx]].v = sv;
            for (int j = 1; j <= N; ++j) {
                if (!vis[j] && Inline(i, j)) {
                    vis[j] = 1; 
                    ++cnt[idx];
                    st += e[j].t, sv += e[j].v;
                    p[idx][cnt[idx]].t = st;
                    p[idx][cnt[idx]].v = sv;
                }
            }
        }
    }
}

void solve()
{
    memset(f, 0, sizeof (f));
    for (int i = 1; i <= idx; ++i) { // 首先考虑到某一组,得到这一组的最佳答案
        for (int t = M; t >= 0; --t) { // 由于一组中只能够取一件物品,所以这个循环在外层 
            for (int j = 1; j <= cnt[i]; ++j) {
                if (t >= p[i][j].t) {
                    f[t] = max(f[t], f[t-p[i][j].t] + p[i][j].v);
                }
            }
        }
    }
    printf("%d\n", f[M]);
}

int main()
{
    int ca = 0;
    while (scanf("%d %d", &N, &M) == 2) {
        for (int i = 1; i <= N; ++i) {
            scanf("%d %d %d %d", &e[i].x, &e[i].y, &e[i].t, &e[i].v);
        }
        sort(e+1, e+1+N);
        printf("Case %d: ", ++ca);
        init();
        solve();
    }
    return 0;    
}
原文地址:https://www.cnblogs.com/Lyush/p/2627241.html