Gym100694A
翻译:给出n个物品,和背包容量m,给出每个物品的价值,重量,和取得这个物品获得的额外的背包容量,可以最多选择两个物品获得额外的背包容量,问最后的最大价值。
代码:
细节极为丰富的一道背包题。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<map>
#include<vector>
#include<string>
#include<algorithm>
#include<cmath>
#include<queue>
#include<set>
using namespace std;
#define maxn 10010
#define mkp make_pair
#define inf 1e6
typedef long long ll;
const ll mod = 1e9 + 7;
const double pi = acos(-1.0);
ll dp[maxn][710][3];
/*
这里的一个启发是:当出现一个特殊条件时可以增加一维数组
联想到18年蓝桥杯国赛“迷宫与陷阱”[链接](https://www.lanqiao.cn/problems/229/learning/)
*/
int n, m;
struct nod
{
ll p, w, d;
bool operator <(nod u)
{
//if (d - w == u.d - u.w) return p < u.p;
return d > u.d;
}
}qq[maxn];
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int i, j, r, l;
ll ans = 0;
cin >> n >> m;
for (i = 1; i <= n; i++)
{
cin >> qq[i].p >> qq[i].w >> qq[i].d;
}
sort(qq + 1, qq + n + 1);//排序必不可少
for (i = 0; i <= m + 200; i++)//初始化
{
for (r = 0; r <= 2; r++)
{
dp[0][i][r] = -1;
}
}
dp[0][m][0] = 0;
for (i = 1; i <= n; i++)
{
for (j = 0; j <= m + 200; j++)
{
for (r = 0; r <= 2; r++)
{
dp[i][j][r] = dp[i - 1][j][r];
}
}
//这里是一个值得关注之处,由于存在d>w的可能性,起始点须从m开始
//j的遍历方向需要与重量递推方向相反
//若是从0开始,则j--,dp[i][j+qq[i].w][r]
for (j = 0; j <= m + 200; j++)
{
for (r = 0; r <= 2; r++)
{
if (dp[i - 1][j][r] != -1 && j >= qq[i].w)
{
dp[i][j - qq[i].w][r] = max(dp[i][j - qq[i].w][r], dp[i - 1][j][r] + qq[i].p);
}
if (r == 0) continue;
if (dp[i - 1][j][r - 1] != -1 && j >= (qq[i].w - qq[i].d))
{
dp[i][j - qq[i].w + qq[i].d][r] = max(dp[i][j - qq[i].w + qq[i].d][r], dp[i - 1][j][r - 1] + qq[i].p);
}
}
}
}
for (i = 0; i <= m + 200; i++)
{
for (r = 0; r <= 2; r++)
{
ans = max(ans, dp[n][i][r]);//细节,重量不一定全用完
}
}
cout << ans << endl;
return 0;
}
但是,本题的数据感觉是存在一定问题的,重载的<应为
if (d - w == u.d - u.w) return p < u.p;
否则,下面的数据会hack掉
4 10
10000 50 21
1000 40 30
1000 40 35
100 1 20
但是,在测评机上WA在了第37个测试点(也有可能是我的题意理解有偏差?)
Clock Master
代码:
比赛的时候,思路被带蒙了,后来才发现是个分组背包
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define maxn 30030
int n, cnt = 0;
double qq[maxn], dp[maxn];
int p[maxn];
bool f[maxn];
vector<int>ww[3300];
double ans[maxn];
void init()
{
for (int i = 2; i <= 30000; i++)
{
if (!f[i])
{
p[++cnt] = i;
}
for (int j = 1; j <= cnt; j++)
{
if (i * p[j] > 30000)
{
break;
}
f[i * p[j]] = 1;
if (!(i % p[j]))
{
break;
}
}
}
}
void fenzu()
{
for (int i = 1; i <= cnt; i++)
{
int tx = p[i];
//ww[i].push_back(tx);
for (int j = 1; tx <= 30000; j++)
{
ww[i].push_back(tx);
tx *= p[i];
}
}
}
void fun()
{
init();
fenzu();
/*for (int i = 1; i <= cnt; i++)
{
cout << p[i] << endl;
}*/
for (int i = 1; i <= 30000; i++) qq[i] = log(i);
for (int i = 1; i <= 30000; i++) dp[i] = -1;
dp[0] = 0;
/*for (int i = 1; i <= cnt; i++)
{
for (int j = 30000; j >= p[i]; j--)
{
if (dp[j - p[i]] >= 0) dp[j] = max(dp[j], dp[j - p[i]] + qq[p[i]]);
}
}*/
for (int k = 1; k <= cnt; k++)
{
for (int j = 30000; j >= 0; j--)
{
for (int i = 0; i < ww[k].size(); i++)
{
if (j < ww[k][i]) break;
if (dp[j - ww[k][i]] >= 0)
{
dp[j] = max(dp[j], dp[j - ww[k][i]] + qq[ww[k][i]]);
}
}
}
}
ans[0] = 0;
for (int i = 1; i <= 30000; i++)
{
ans[i] = max(ans[i - 1], dp[i]);
}
}
int main()
{
//freopen("in.txt","r",stdin);
int T, i, j;
cin >> T;
fun();
//cout << cnt << endl;
while (T--)
{
cin >> n;
printf("%.8lf\n", ans[n]);
}
}