hdu 4341(分組揹包(好題))

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=4341

分組揹包問題, 由於一條直線上的要按照順序取, 如果一條直線上有n個金礦, 對於這條直線則有n + 1 種決策, 而且是互相矛盾的, 所以可以將這n個物品重新組合一下, 轉化成一個分組揹包問題, 詳見代碼。。。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <vector>
#include <cmath>
#include <cstdlib>

using namespace std;

const int N = 205;

struct Point {
	int x, y, t, v;	

	bool operator <(const Point& p) const {
		return labs(x) + labs(y) < labs(p.x) + labs(p.y);
	}
};

Point pts[N];
bool flag[N];
vector<Point> group[N];
int dp[40005];

int main() {
	int n, W, cas = 1, g;
	while (~scanf("%d%d", &n, &W)) {
		for (int i = 0; i < n; i++)
			scanf("%d%d%d%d", &pts[i].x, &pts[i].y, &pts[i].t, &pts[i].v);
		memset(flag, 0, sizeof(flag));

		g = 0;
		for (int i = 0; i < n; i++)
			group[i].clear();

		for (int i = 0; i < n; i++) {
			if (flag[i]) continue;
			Point cur = pts[i];
			group[g].push_back(cur);
			for (int j = i + 1; j < n; j++)
				if (cur.x * pts[j].y - cur.y * pts[j].x == 0 && !flag[j]) {
					group[g].push_back(pts[j]);
					flag[j] = 1;
				}
			g++;
		}

		for (int i = 0; i < g; i++) {
			sort(group[i].begin(), group[i].end());
			int m = group[i].size();
			if (m == 1) continue;
			for (int j = 1; j < m; j++) {
				group[i][j].t += group[i][j - 1].t;
				group[i][j].v += group[i][j - 1].v;
			}
		}

		fill(dp, dp + W + 1, 0);
		for (int i = 0; i < g; i++)
			for (int j = W; j >= 0; j--)
				for (int k = 0; k < group[i].size(); k++)
					if (j - group[i][k].t >= 0)
						dp[j] = max(dp[j], dp[j - group[i][k].t] + group[i][k].v);


		printf("Case %d: %d\n", cas++, dp[W]);
	}
	return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章