【hdu 3177 Crixalis's Equipment】 题解
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3177
\(describe\):
有一个山洞,山洞的容积最大为\(v\)。现在你有\(n\)个物品,这些物品在往山洞里搬和放在山洞所需要占用山洞的体积是两个不同的值\(B\),\(A\)。你可以理解为在搬运这个物品进洞时需要的容积为一个\(B\),放下物品后的容积是一个\(A\)。在任何时刻搬运物品都不允许超过山洞的最大容积。试求能不能把所有物品搬进去
题解:
这个题正解是贪心...没错...
题目只问的是能不能都放完,我们贪心地往里放物品看看能不能放完就好了。
证明:
~~zhx的证明法: ~~
——贪心题都是排序题。
设只有两个物品a,b
要么先放a,要么先放b,反正两种放法
考虑若先放a的话 当前v要 > a.B 放了a.A
然后放b 放了b.B 结果 a.A+b.B
复读:
考虑若先放b的话 当前v要 > b.B 放了b.A
然后放a 放了a.B 结果 b.A+a.B
比较两个结果取min就ok了啊
操作?
如果排序a,b
放的顺序是a,b
那么就会是a.A+b.B < b.A+a.B
你把这俩反着证明也一样,自己明白咋排序就行,实在不行排上几种序什么a.A+a.B<b.A+b.B a.A-a.B<b.A-b.B......取个min
看心情化简:a.A-a.B < b.A-b.B
code:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1e7;
int n, v, ans, T;
struct thing{
int B, A;
}e[maxn];
bool cmp(thing a, thing b)
{
return a.A + b.B < b.A + a.B;
}
int main()
{
ios::sync_with_stdio(false);
cin>>T;
while(T--)
{
ans = 0;
cin>>v>>n;
for(int i = 1; i <= n; i++)
cin>>e[i].A>>e[i].B;
sort(e+1, e+1+n, cmp);
for(int i = 1; i <= n; i++)
if(e[i].B <= v)
{
ans++;
v -= e[i].A;
}
if(ans == n) cout<<"Yes\n";
else cout<<"No\n";
}
return 0;
}
考虑变式一下:
如果是求最多能放多少物品呢?
那就是DP了。
如果能放完的话,第一个是一定会放进去的,所以用贪心判断能不能放完是可以的,但是如果求最多放进去数量的话,我们第一个选不选是不确定的,所以需要跑一个01背包。
但是..DP?需要无后效性的。
那么最优的序列,就是我们贪心排序过后的序列。
好了,在这个序列上跑一个背包。
但是我们在进行状态转移的时候,需要控制一下。
设\(dp[j]\) 表示已经放满\(j\)容积时的能放下的最多的物品数
那么转移方程就是\(dp[j] = max(dp[j], dp[j-a[i].A]+1)\)
转移要满足一开始能搬进这个东西来,所以又有:
\(if(v - (j - a[i].A) >= a[i].B)\)
j是当前使用的容积(包含着搬进后的物品容积,所以j-a[i].A),再用v减去,就是剩下的。
于是:
code:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1000;
int dp[maxn], n, v, ans;
struct thing{
int A, B;
}a[maxn];
bool cmp(thing a, thing b)
{
return a.A - a.B < b.A - b.B;
}
int main()
{
cin>>n>>v;
for(int i = 1; i <= n; i++) cin>>a[i].B>>a[i].A;
sort(a+1, a+1+n, cmp);
for(int i = 1; i <= n; i++)
{
for(int j = v; j >= a[i].A; j--)
{
if(v - (j - a[i].A) >= a[i].B)
dp[j] = max(dp[j-a[i].A] + 1, dp[j]);
ans = max(dp[j], ans);
}
}
cout<<ans;
return 0;
}
//MisakaAzusa
//dsbdsb
隐约雷鸣,阴霾天空,但盼风雨来,能留你在此。
隐约雷鸣,阴霾天空,即使天无雨,我亦留此地。