题目描述
有n(2<=n<=20)头奶牛在玩飞盘,可是飞盘飞到了高处。现在他们要想办法叠在一起,去取飞盘。飞盘的高度为H(1 <= H <= 1,000,000,000)。给出每头奶牛的重量、高度、强壮度(能够承受的重量),问他们是否够得到,如果能够取到,求它们额外还能承受最多多少重量。(要保证每头奶牛所承受的重量都不超过它的强壮度)。
输入
输入格式:
第一行包含N和H。
接下来N行,每行三个数,分别表示它的高度、重量和强壮度。所有的数都为正整数。
输出
输出格式:
如果奶牛的队伍可以够到飞盘,输出还能承受的最大额外重量;否则输出“Mark is too tall”.
样例输入
4 10 9 4 1 3 3 5 5 5 10 4 4 5
样例输出
2
解题思路
重点看数据,事实证明一道题目还是要根据数据范围来的,数据中N<=20,数据量太小了,似乎可以用dfs做,做全排。全排的时间复杂度这么高,肯定是不可能的,因此我们不需要考虑什么暴力全排,但这道题要用dfs,这是肯定的。我们就要想到优化yi下,首先,这里不能用什么记忆化,这里与dp是无太大关系的。
其实看这个题目,我们凭借常识就会觉得,理想状况是,越往上的奶牛,强壮度都会小,下面的奶牛强壮度肯定高,如果上面的奶牛重量更小就是最好了。那么,其实最优情况就是强壮度和奶牛重量小的在上面,那么我们便以此排序?
现在我们假设有一堆牛了,它们可以承受W的重量。此时要放上i,j两头牛
(一)先放i,再放j。 新的承受值就为 min(W - w[i] - w[j] , c[i] - w[j])
(二)先放j,再放i。 新的承受值就为 min(W - w[j] - w[i] , c[j] - w[i])
有人会问为什么会有后面那一块,其实这里承受值W阐述起来有些复杂,你这样想,就是(塔内每一头牛的强壮度 - 往上的所有牛的重量)的最小值。
这样我们两种情况如果比较起来就是比较 (c[i] - w[j] , c[j] - w[i])了。我们要让承受值尽量大,因此在这两个里面求最大值。
移一下项,就是求max(c[i] + w[i] , c[j] + w[j])了。自然,好一点的牛我们优先往下放,不要小看这一个排序,可以大大减小时间,我们可以这样想一下。最优的放在下面,如果这个最优的不用了,那么就可以不用管了,因为如果放在上面的话,反而是最差的选择。因此,我们再考虑第i头牛的时候,1到i - 1的所有牛就不用管了。
于是暴力也就很好打了。
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<vector>
#include<queue>
#include<algorithm>
#include<map>
#include<set>
#include<cstdlib>
using namespace std;
struct node{
long long ht,w,c;
bool operator <(const node &b)const{//重载较为好用
return b.w + b.c < w + c;
}
}a[25];
int h,n;
long long dfs_h,dfs_w , ans = -1;
long long read(){
long long f = 1 ,x = 0;
char s = getchar();
while (s < '0' || s > '9'){
if (s == '-')
f = -1;
s = getchar();
}
while (s >= '0' && s <= '9'){
x = x * 10 + s - '0';
s = getchar();
}
return x * f;
}
void dfs(int step){
if (dfs_h >= h){//如果已符合条件,可以不用再放了
ans = max (ans ,dfs_w);
return ;
}
if (step > n)//超过了就不再管。
return ;
if (dfs_w >= a[step].w){//如果可以放,就尝试一下,标准dfs回溯操作
long long t = dfs_w;
dfs_w = min(dfs_w - a[step].w,a[step].c);
dfs_h += a[step].ht;
dfs(step + 1);
dfs_w = t ;
dfs_h -= a[step].ht;
}
dfs(step + 1);//跳过此点尝试是否有更优
}
int main(){
n = read();
h = read();
for (int i = 1;i <= n;i ++ ){
a[i].ht = read();
a[i].w = read();
a[i].c = read();
}
sort (a+1,a+1+n);//这里用重量+强壮度进行排序
dfs_w = 1e15;
dfs(1);
if (ans != -1)
printf("%lld",ans);
else
printf("Mark is too tall");
}
总结
这道题看起来似乎有些奇怪,确实,算法考的是贪心排序和dfs,只能说,平时的时候,dfs看起来全然是暴力,但有些时候,搜索确实是一种比较有用的算法,至少在有些方面,用搜索进行对拍也是一种不错的选择。考试的时候,这道题没怎么看,最终还是连题目都没怎么看懂,总觉得还是挺复杂的。乍一看可能要DP来做。但如果我细细想想,或者说看一看题,我估计再怎么暴力还是可以做一下的,事实证明。。。。至于证明了什么,你们可以看出来。