JS禁止查看网页源代码的简单实现方法

JZOJ 小奇采药 (深度优先搜索-dfs)

来源:JZOJ

题目描述

小奇是只天资聪颖的喵,他的梦想是成为世界上最伟大的医师。

为此,他想拜喵星球最有威望的医师为师。

医师为了判断他的资质,给他出了一个难题。

医师把他带到一个到处都是草药的山洞里对他说:

“小奇,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。

我会给你一段时间,在这段时间里,你可以采到一些草药。

如果你是一只聪明的喵,你应该可以让采到的草药的总价值最大。”

解题思路

  • 这道题乍一看,还以为就是个背包的模板题,细细一看...不就是道模板题嘛!
  • 信心满满地以瞬雷不及掩耳之势 打好了代码,提交!!!
  • \(30\) 分!\(QAQ\)
  • 原来,这道题 要用 搜索!
  • 哈哈!惊异到了吧!让我们来正经地理一下思路:
  • 数据有点坑,所以,有请 \(dfs\) 中的玄学——剪枝 登场!
  • 先按时间从大到小排序,求一个后缀和,\(sw[i]\) 表示 \(i\)\(n\) 的时间和,\(sv[i]\) 表示 \(i\)\(n\) 的价值和,然后就做一个背包的 \(dfs\) 吧!

剪枝技巧:

  • First:如果当前的时间和加上 \(a[n].w\) 还超过了背包容量,也就是不管那哪一件往背包里塞都装不下了,就退出
  • Second:如果当前的价值和加上 \(sv[x]\) 也就是说 \(x\) 后的价值和仍然小于最优值,就退出
  • Third:如果当前的时间和加上 \(sw[x]\) 也就是说 \(x\) 后的时间和小于背包容量,就拿当前的价值和加上 \(sv[x]\) 和原最优解比较,如果当前的更优,更新,这时候就没有再递归下去的必要了,直接退出
  • :也许思路有些别扭,静下心来,仔细思考一下,这三个剪枝是很有效的

Code

#include <bits/stdc++.h>
using namespace std;
long long ans=0;
long long sw[205],sv[205];
int n;
long long m;
struct node
{
	int w,v;
}a[205];
inline int read()  //快读
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
bool mycmp(node a,node b)
{
	return a.w>b.w;
}
void dfs(int x,long long sumw,long long sumv)
{
	ans=max(ans,sumv);
	if (sumw+a[n].w>m) return;  //三个剪枝,上文已给出
	if (sumv+sv[x]<ans) return;
	if (sumw+sw[x]<=m)
	{
		ans=max(ans,sumv+sv[x]);
		return;
	}
	if (sumw+a[x].w<=m) dfs(x+1,sumw+a[x].w,sumv+a[x].v);  //如果可以取当前这个,递归
	dfs(x+1,sumw,sumv);  //不取
}
int main()
{
	freopen("herb.in","r",stdin);
	freopen("herb.out","w",stdout);
	int T;
	T=read();
	for (int t=1;t<=T;t++)
	{
		scanf("%d %lld",&n,&m);
		for (int i=1;i<=n;i++) scanf("%d %d",&a[i].w,&a[i].v);
		sort(a+1,a+n+1,mycmp);  //按时间从大到小排序
		sw[n+1]=0; sv[n+1]=0;  //初值,因为是递推,所以没必要memset
		for (int i=n;i>=1;i--)  //后缀和
		{
			sw[i]=sw[i+1]+a[i].w;
			sv[i]=sv[i+1]+a[i].v;
		}
		ans=0;
		dfs(1,0,0);
		printf("%lld\n",ans);  //输出最优值
	}
	return 0;
}
posted @ 2020-02-24 17:15  Z__X  阅读(294)  评论(0编辑  收藏  举报