您的位置:首页 > 其它

B. Shaass and Bookshelf DP

2016-12-30 22:30 211 查看
http://codeforces.com/contest/294/problem/B

据说是贪心,我用了一个复杂度是2e8的dp水过去了。

其实这题就是给你n个数,每个数有两个权值,分成两组,使得第一个权值之和,和第二个权值之和的最大值最小。

那么直接设dp[i][j][k][h]表示前i个数中,选了j个,第一个权值的和是k,第二个权值是h,是否可能。

这里是一定要选出n个的,就是n个数都必须使用,才能滚动数组。(把第二维滚动)

如果是从n个数中选出k个,那么就不能滚动了。

那么第一维是01背包直接省略,j那里可以滚动数组。

总复杂度2e8

然后题解是贪心......

还有要注意,k要大于h,就是底下的书要长于上面的书。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <assert.h>
#define IOS ios::sync_with_stdio(false)
using namespace std;
#define inf (0x3f3f3f3f)
typedef long long int LL;

#include <iostream>
#include <sstream>
#include <vector>
#include <set>
#include <map>
#include <queue>
#include <string>
struct node {
int ti, wi;
}a[111];
int dp[2][200 + 2][10000 + 2];
void work() {
int n;
cin >> n;
int DFN = 1;
int sumti = 0, sumwi = 0;
for (int i = 1; i <= n; ++i) {
cin >> a[i].ti >> a[i].wi;
sumti += a[i].ti;
sumwi += a[i].wi;
}
if (n == 1) {
cout << min(a[1].ti, a[1].wi) << endl;
return;
}
//    sort(a + 1, a + 1 + n);
dp[0][0][0] = DFN;
int now = 0;
for (int i = 1; i <= n; ++i) {
now = !now;
++DFN;
for (int j = sumti; j >= 0; --j) {
for (int k = sumwi; k >= 0; --k) {
if (j >= a[i].ti && dp[!now][j - a[i].ti][k] == DFN - 1) {
dp[now][j][k] = DFN;
}
if (k >= a[i].wi && dp[!now][j][k - a[i].wi] == DFN - 1) {
dp[now][j][k] = DFN;
}
}
}
}
int ans = inf;
for (int i = 0; i <= sumti; ++i) {
for (int j = 0; j <= i; ++j) {
if (dp[now][i][j] == DFN) {
ans = min(ans, max(i, j));
}
}
}
cout << ans << endl;
}

int main() {
#ifdef local
freopen("data.txt", "r", stdin);
//    freopen("data.txt", "w", stdout);
#endif
work();
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: