[BZOJ 1082] [SCOI2005] 栅栏 【二分 + DFS验证(有效剪枝)】
题目链接:BZOJ - 1082
题目分析
二分 + DFS验证。
二分到一个 mid ,验证能否选 mid 个根木棍,显然要选最小的 mid 根。
使用 DFS 验证,因为贪心地想一下,要尽量先用提供的小的木木棍,尽量先做出需要的大的木棍,所以要先将提供的木棍和需要的木棍都排序。
DFS 的时候是按照需要的木棍从大到小的顺序一层一层搜,每一层上是按照从小到大的顺序枚举提供的木棍。(当然枚举的时候已经不一定是从小到大了,有些木棍已经被截掉了一些。)
要使用两个有效的剪枝:
1)如果下一层的木棍和这一层的木棍等长,就从这一层木棍枚举到的提供的木棍开始枚举,因为前面的都是不可以的。
2)当一根木棍被截掉一段之后小于最小的需要的木棍,那么它就废掉了,记录当前废掉的木棍总长Rest,如果Rest + 1到mid所有木棍的总长 > 提供的所有木棍总长,那么就返回 false。
代码
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath> using namespace std; const int MaxM = 50 + 5, MaxN = 1000 + 5; int n, m, Ans, Rest, Need, Tot;
int A[MaxM], B[MaxN], Sum[MaxN]; bool DFS(int x, int y)
{
if (Rest + Need > Tot) return false;
bool ret = false;
for (int i = y; i <= m; ++i)
{
if (A[i] >= B[x])
{
A[i] -= B[x];
if (A[i] < B[1]) Rest += A[i];
if (x == 1) ret = true;
else if (B[x - 1] == B[x]) ret = DFS(x - 1, i);
else ret = DFS(x - 1, 1);
Rest -= A[i];
A[i] += B[x];
if (ret) return true;
}
}
return false;
} int main()
{
scanf("%d", &m);
for (int i = 1; i <= m; ++i) scanf("%d", &A[i]);
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &B[i]);
sort(A + 1, A + m + 1);
for (int i = 1; i <= m; ++i) Tot += A[i];
sort(B + 1, B + n + 1);
for (int i = 1; i <= n; ++i) Sum[i] = Sum[i - 1] + B[i];
int l, r, mid;
l = 0; r = n;
Ans = 0;
while (l <= r)
{
mid = (l + r) >> 1;
Need = Sum[mid];
Rest = 0;
if (DFS(mid, 1))
{
Ans = mid;
l = mid + 1;
}
else r = mid - 1;
}
printf("%d\n", Ans);
return 0;
}
[BZOJ 1082] [SCOI2005] 栅栏 【二分 + DFS验证(有效剪枝)】的更多相关文章
- bzoj 1082: [SCOI2005]栅栏 题解
1082: [SCOI2005]栅栏 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2340 Solved: 991[Submit][Status] ...
- 【BZOJ 1082】[SCOI2005]栅栏 二分+dfs
对于最优解我们发现所有的最优解都可以是前多少多少个,那么我们就二分这个前多少多少个,然后用dfs去判解,我们发现在dfs的过程中如果不剪枝几乎必T,所以我们就需要一些有效的剪枝 I. 我们在枚举过程中 ...
- bzoj 1082: [SCOI2005]栅栏【二分+dfs】
二分答案,dfs判断是否可行,当b[k]==b[k-1]时可以剪枝也就是后移枚举位置 #include<iostream> #include<cstdio> #include& ...
- bzoj 1082: [SCOI2005]栅栏
Description 农夫约翰打算建立一个栅栏将他的牧场给围起来,因此他需要一些特定规格的木材.于是农夫约翰到木材店购 买木材.可是木材店老板说他这里只剩下少部分大规格的木板了.不过约翰可以购买这些 ...
- [SCOI2005]栅栏 二分+dfs
这个题真的是太nb了,各种骚 二分答案,肯定要减最小的mid个,从大往小搜每一个木板,从大往小枚举所用的木材 当当前木材比最短的木板还短,就扔到垃圾堆里,并记录waste,当 waste+sum> ...
- bzoj1082: [SCOI2005]栅栏(二分答案搜索判断)
1082: [SCOI2005]栅栏 题目:传送门 题解: 是不是一开始在想DP?本蒟蒻也是qwq,结果很nice的错了ORZ 正解:二分+搜索 我们可以先把两种木材都进行排序,那么如果需要的最大木材 ...
- [BZOJ1082][SCOI2005]栅栏 二分+搜索减枝
1082: [SCOI2005]栅栏 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2430 Solved: 1034[Submit][Status ...
- Bzoj 1085: [SCOI2005]骑士精神 (dfs)
Bzoj 1085: [SCOI2005]骑士精神 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=1085 dfs + 剪枝. 剪枝方法: ...
- 1082: [SCOI2005]栅栏
链接 思路 二分+搜索+剪枝. 首先二分一个答案,表示最多可以切出x块.(一个结论:切出的一定是从较小的前x块.如果一个木材可以满足很多个需要的木材,那么切出最小的,就意味着以后再选时的机会更多.) ...
随机推荐
- android80 HttpClient框架提交数据 get方式
package com.itheima.httpclient; import java.io.IOException; import java.io.InputStream; import java. ...
- Hack工具
黑客工具一般是由黑客或者恶意程序安装到您计算机中,用来盗窃信息.引起系统故障和完全控制电脑的恶意软件程序.同时也指黑客进行黑客任务时使用的工具.著名的有nmap,流光等等. 目录 1 种类 2 恶意程 ...
- php快速排序
快速排序是排序中常用的,效率据说还不错,它使用分治算法实现 将一个大的需要排序的序列,分成两个较小的序列!怎么分呢,需要从序列中找出一个元素作为参考元素,通常的做法是拿第一个元素作为参考元素.当一个序 ...
- Spring入门Hello World
这里是关于Hello World的一些基本的操作 Spring 是一个重量级的容器框架,用来配置bean并维护bean之间的关系的框架 想要最初的使用Spring就要学会最基本的配置 <1> ...
- 根据文件夹的GUid找到该文件夹
Guid guid = Guid.Parse(folderGuID); SPFolder folder = list.Folders[guid].Folder;
- js基础知识之_对象
javascript 对象 1.基于对象 一切皆对象,以对象的概念来编程 2.面向对象的编程(oop,Object oriented programming) 1.对象 就是人们要研究的任何事物,不仅 ...
- 详细介绍Linux shell脚本基础学习
Linux shell脚本基础学习这里我们先来第一讲,介绍shell的语法基础,开头.注释.变量和 环境变量,向大家做一个基础的介绍,虽然不涉及具体东西,但是打好基础是以后学习轻松地前提.1. Lin ...
- Object-C — KVO & oc通知
键值观察(KVO)是基于键值编码的一种技术. 利用键值观察可以注册成为一个对象的观察者,在该对象的某个属性变化时收到通知. 被观察对象需要编写符合KVC标准的存取方法,编写键值观察分为以下三步: (1 ...
- Codevs 1337 银行里的迷宫
1337 银行里的迷宫 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 白银 Silver 传送门 题目描述 Description 楚楚每一次都在你的帮助下过了一关又一关(比如他开 ...
- boost::xml——基本操作以及中文乱码解决方案 (续)
本博文主要想说明以下两点: 1.对于上一篇的<boost::xml——基本操作以及中文乱码解决方案>解释,这篇博文基本解决了正确输入输出中英文问题,但是好像还没有解决修改中文出现乱码的问题 ...