思路:100个物品的背包问题,其他数值都在1e9
迷之剪枝:维护两个前缀和,如果后面能取完的就直接取完,如果后面能获得的最大价值加上已有的都没有比现在的答案更优那么返回。按照体积由大到小排序,其他排序方法都会T?这是为什么呢
#include
using namespace std;
const int maxn = 105;
#define LL long long
int n,V;
LL sumw[maxn],sumv[maxn];
struct Node
{
int w,v;
double rate;
}bag[maxn];
bool cmp(Node a,Node b)
{
//return a.rate>b.rate;
return a.v>b.v;
}
LL ans = 0;
void dfs(int pos,int limit,LL get)
{
if(pos==n)
{
if(limit>=bag[pos].v)
ans = max(ans,(LL)get+bag[pos].w);
else
ans = max(ans,get);
return;
}
if(sumv[pos]<=limit)
{
ans = max(ans,get+sumw[pos]);
return;
}
if(get+sumw[pos]<=ans)
return;
dfs(pos+1,limit,get);
if(limit>=bag[pos].v)
dfs(pos+1,limit-bag[pos].v,get+bag[pos].w);
}
int main()
{
while(scanf("%d%d",&n,&V)!=EOF)
{
ans = 0;
sumw[n+1]=0;
sumv[n+1]=0;
for(int i = 1;i<=n;i++)
{
scanf("%d%d",&bag[i].v,&bag[i].w);
bag[i].rate = 1.0*bag[i].w/(double)bag[i].v;
}
sort(bag+1,bag+n+1,cmp);
for(int i = n;i>=1;i--)
{
sumw[i]=sumw[i+1]+bag[i].w;
sumv[i]=sumv[i+1]+bag[i].v;
}
dfs(1,V,0);
printf("%lld\n",ans);
}
}
附上一个0MS的代码
#include
#include
#include
using namespace std;
int n, vLimit, v[100], w[100];
long double rate[100];
long long wBest;
void swap(int i, int j) {
int tmp;
tmp = v[i];
v[i] = v[j];
v[j] = tmp;
tmp = w[i];
w[i] = w[j];
w[j] = tmp;
double tmp2;
tmp2 = rate[i];
rate[i] = rate[j];
rate[j] = tmp2;
}
void sort() {
for (int i = 0; i < n; ++ i) {
for (int j = i + 1; j < n; ++ j) {
if (rate[i] < rate[j]) swap(i, j);
}
}
}
bool can_cut(int k, int _vCurrent, long long _wCurrent) {
long double vCurrent = _vCurrent;
long double wCurrent = _wCurrent;
for (int i = k; i < n && vCurrent < vLimit; ++ i) {
if (vCurrent + v[i] < vLimit) {
vCurrent += v[i];
wCurrent += w[i];
} else {
wCurrent += rate[i] * (vLimit - vCurrent);
vCurrent = vLimit;
}
}
return wCurrent < wBest;
}
void search(int k, int vSum, long long wSum) {
if (wSum > wBest) {
wBest = wSum;
}
if (k < n && !can_cut(k, vSum, wSum)) {
if ((long long)vSum + v[k] <= vLimit) {
search(k + 1, vSum + v[k], wSum + w[k]);
}
search(k + 1, vSum, wSum);
}
}
int main() {
while (scanf("%d%d", &n, &vLimit) != EOF) {
for (int i = 0; i < n; ++ i) {
scanf("%d%d", &v[i], &w[i]);
rate[i] = (long double)w[i] / (long double)v[i];
}
sort();
wBest = 0;
search(0, 0, 0);
std::cout << wBest << std::endl;
}
}