贪心+二分解决最大值最小、最小值最大问题

2023-11-16

 

在刷题时,总会遇到求最大值最小,最小值最大问题,也许它会暗喻是这样的一个问题。对于这样的一个问题,你会发现用dp和枚举都会超时超内存,或者说很麻烦,所以这是一个比较简单的解题方式。

二分逼近思想

对于难以直接确定解的问题,采取二分枚举+检验的思想.

已知解为x,验证x是否满足要求.

如果答案具有特定的范围,并且验证答案是否成立的函数具有单调性。则可以在范围内对答案进行二分验证,从而快速确定答案。

 对于答案判断:

在二分答案的时候需要判断,从而确定下一个范围。

可以用一个bool Check(x)函数来判断,返回true表示满足,返回false表示不满足.

可以类比数学函数f(x)>=0f(x)<0来理解.

根据具体问题写出相应的Check函数往往就是解决问题的关键点。

下面举例一些问题:

poj2456

Aggressive cows

Time Limit: 1000MS   Memory Limit: 65536K
Total Submissions: 13139   Accepted: 6399

 

Description

Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,...,xN (0 <= xi <= 1,000,000,000). 

His C (2 <= C <= N) cows don't like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?

Input

* Line 1: Two space-separated integers: N and C 

* Lines 2..N+1: Line i+1 contains an integer stall location, xi

Output

* Line 1: One integer: the largest minimum distance

Sample Input

5 3
1
2
8
4
9

Sample Output

3

Hint

OUTPUT DETAILS: 

FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3. 

Huge input data,scanf is recommended.

Source

USACO 2005 February Gold

 

2.题意概述:

农夫有c头牛,n个隔间,c头牛很躁动,很容易相互打架,因此农夫想把它们分得越远越好,要你分配隔间使得相邻两头牛的距离越远越好,问你这c头牛分割的最小距离的最大值。

3.解题思路: 

先对隔间的坐标排序,对于牛,最小距离是0,最大距离不会超过两端两头牛的距离值,因此二分地查找分割距离的最大值,每次mid都judge一次,judge的时候贪心地放置牛,保证前i头牛是符合这样分割标准的。

AC代码:

 

#include<iostream>
#include<algorithm>
using namespace std;
	int n,k,t;
	int a[100000];
bool fun(int d){
	int next,last=0,k=1;
	for(int i=1;i<t;i++){
		if(a[i]-a[last]>=d){
			k++;
			last=i;
		}
	}
	if(k>=n)
		return true;
	else
		return false;
}
int main(){
cin>>t;
cin>>n;
	for(int i=0;i<t;i++)
		cin>>a[i];
	sort(a,a+t);
	int l=0,r=a[t-1],mid=(l+r)/2;
	while(l<=r){
		if(fun(mid)){
			l=mid+1;
		}
		else{
			r=mid-1;	
		}
		mid=(l+r)/2;
	
	}
	cout<<r<<endl;
	return 0;
} 

 

 

 

 

 

poj1505 

Copying Books

Time Limit: 3000MS   Memory Limit: 10000K
Total Submissions: 9632   Accepted: 3013

Description

Before the invention of book-printing, it was very hard to make a copy of a book. All the contents had to be re-written by hand by so called scribers. The scriber had been given a book and after several months he finished its copy. One of the most famous scribers lived in the 15th century and his name was Xaverius Endricus Remius Ontius Xendrianus (Xerox). Anyway, the work was very annoying and boring. And the only way to speed it up was to hire more scribers. 

Once upon a time, there was a theater ensemble that wanted to play famous Antique Tragedies. The scripts of these plays were divided into many books and actors needed more copies of them, of course. So they hired many scribers to make copies of these books. Imagine you have m books (numbered 1, 2 ... m) that may have different number of pages (p1, p2 ... pm) and you want to make one copy of each of them. Your task is to divide these books among k scribes, k <= m. Each book can be assigned to a single scriber only, and every scriber must get a continuous sequence of books. That means, there exists an increasing succession of numbers 0 = b0 < b1 < b2, ... < bk-1 <= bk = m such that i-th scriber gets a sequence of books with numbers between bi-1+1 and bi. The time needed to make a copy of all the books is determined by the scriber who was assigned the most work. Therefore, our goal is to minimize the maximum number of pages assigned to a single scriber. Your task is to find the optimal assignment. 

Input

The input consists of N cases. The first line of the input contains only positive integer N. Then follow the cases. Each case consists of exactly two lines. At the first line, there are two integers m and k, 1 <= k <= m <= 500. At the second line, there are integers p1, p2, ... pm separated by spaces. All these values are positive and less than 10000000.

Output

For each case, print exactly one line. The line must contain the input succession p1, p2, ... pm divided into exactly k parts such that the maximum sum of a single part should be as small as possible. Use the slash character ('/') to separate the parts. There must be exactly one space character between any two successive numbers and between the number and the slash. 

If there is more than one solution, print the one that minimizes the work assigned to the first scriber, then to the second scriber etc. But each scriber must be assigned at least one book.

Sample Input

2
9 3
100 200 300 400 500 600 700 800 900
5 4
100 100 100 100 100

Sample Output

100 200 300 400 500 / 600 700 / 800 900
100 / 100 / 100 / 100 100

 

题意:按顺序给你N个数,将这N个数分成连续的M段,使得这M段每段的和中的最大值最小,输出最小值(1<=N<=100000,1<=M<=N,每个数在1到10000之间),如果有多种可能的话,尽量在前面进行划分。(其实第一次读题还不知道是什么意思,仔细琢磨才明白是这样的一个问题)

首先以正常的思路去考虑优化这个最大值的最小化问题,好像会陷入到循环之中找不到解决的思路,但是我们如果采用猜测-判断-重来的方法不断的去尝试二分查找最大值的最小值,然后去判断这个值是否合法,进一步优化这个值,就可以解决。

ac代码:

#include<iostream>
using namespace std;
int a[501];
int t,m,n;
int yes_no(int dis,int flag){
	int last=0,next=0,tsum=a[last],cnt=1;
	while(next<m){
		if(tsum<=dis){
			next++;
			tsum=tsum+a[next];
		}
		if(tsum>dis){
			cnt++;
			last=next;
			tsum=a[last];
		}
		
	}
//	cout<<cnt<<endl;
	if(cnt>flag)
		return 2;
	else if(cnt==flag)
		return 1;
	else
		return 0;
}
int main(){
	cin>>t;
	while(t--){
		int sum=0,ans;
		cin>>m>>n;
		for(int i=0;i<m;i++){
			cin>>a[i];
			sum+=a[i];
		}
		//cout<<sum<<endl;
		int l=0,r=sum,mid;
		//cout<<mid<<endl;	
		while(l<=r){
			mid=(l+r)>>1;
			if(yes_no(mid,n)==2){
				l=mid+1;
				//cout<<"1";
			}
			else if(yes_no(mid,n)==1){
				ans=mid;
				r=mid-1;
			}
			else{
				r=mid-1;
			//	cout<<"2";
			}
		}
		//cout<<ans<<endl;
		int tsum=0;
		int tn=n-1;
		for(int i=0;i<m;i++){
			tsum+=a[i];
			if(tsum>=ans&&tn){
				tn--;
				cout<<" /";
				tsum=a[i];
			}
			if(i==0){
				cout<<a[i];
			}
			else
				cout<<" "<<a[i];				
		}	cout<<endl;	
	}
	
} 

以上就是这两题,是基本的贪心+二分的求法。 

注意:二分是在排序好的基础上进行的查找,所以,看清题目,尽量先排好序。。。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

贪心+二分解决最大值最小、最小值最大问题 的相关文章

  • CSS学习(六)

    定位 为什么需要定位 提问 以下情况使用标准流或者浮动能实现吗 某个元素可以自由的在一个盒子内移动位置 并且压住其他盒子 当我们滚动窗口的时候 盒子是固定屏幕某个位置的 以上效果 标准流或浮动都无法快速实现 此时需要定位来实现 所以 浮动可
  • vscode 检查c代码语法和补全_VScode下搭配ESLint、TSLint、stylelint的代码检查配方

    使用VScode打开项目时 避免项目路径过深 尽量做到开发a项目就打开a项目 如 dir path path a这样的路径 不要vscode打开 dir来开发 a 因为可能会导致eslint的一些提示出现不准确的现象 关键词 ESLint配

随机推荐

  • tensorflow4:创建一个简单的强化学习游戏

    Deep Q Network是DeepMind最早 2013年 提出来的 是深度强化学习方法 最开始AI什么也不会 通过给它提供游戏界面像素和分数 慢慢把它训练成游戏高手 这里首先给出一个基本的游戏例子 然后再给出强化学习方法 1 基本游戏
  • elementui 计数器

    输入值超过规定的最大值 比如999 输入1000时 输入后 直接提交表单 中间计数器会自动把1000转化为999 再提交 测试人员说没有出现 不能超过3位数字的提示 解决办法 把min和max去掉 再写自定义验证规则就可以了 计数器自动转化
  • JavaScript:iterable类型

    遍历Array可以采用下标循环 遍历Map和Set就无法使用下标 为了统一集合类型 ES6标准引入了新的iterable类型 Array Map和Set都属于iterable类型 具有iterable类型的集合可以通过新的for of循环来
  • 向量积(叉积)及其计算

    定义 两个向量a和b的 向量积 外积 叉积 是一个向量 记作a b 这里 并不是乘号 只是一种表示方法 与 不同 也可记做 若a b不共线 则a b的模是 a b a b sin a b a b的方向是 垂直于a和b 且a b和a b按这个
  • 【Linux】基于单例模式懒汉实现方式的线程池

    需要云服务器等云产品来学习Linux的同学可以移步 gt 腾讯云 lt gt 阿里云 lt gt 华为云 lt 官网 轻量型云服务器低至112元 年 新用户首次下单享超低折扣 目录 一 LockGuard hpp 二 Task hpp 三
  • 二叉查找树(BST)的基本概念及常用操作

    二叉查找树 二叉查找树 Binary Search Tree 也称二叉搜索树 有序二叉树 ordered binary tree 排序二叉树 orted binary tree 是指一棵空树或者具有下列性质的二叉树 若任意节点的左子树不空
  • 有效的括号 力扣 栈应用

    上班摸鱼打代码 o 目录 题目描述 AC代码 思路分析 题目描述 给定一个只包括 的字符串 s 判断字符串是否有效 有效字符串需满足 左括号必须用相同类型的右括号闭合 左括号必须以正确的顺序闭合 示例 1 输入 s 输出 true示例 2
  • HECI-Securtiy 防火墙路由技术

    目录 一 防火墙路由基本原理 1 路由分类 2 路由优先级 3 路由查询先后顺序 4 静态路由基本原理 1 指定出接口场景 2 指定下一跳地址场景 5 静态路由与多出口 1 主备备份 2 均衡式负载分担 3 溢出式负载分担 二 逐流与逐包报
  • 2022年实习面试 凉经

    2022年实习面试 凉经 字节跳动 数据分析师 2022 8 3 首先是自我介绍 其次给我出了一道sql的题目 里面用到了group by 的分组函数 以及最好嵌套一个子查询 然后出了一道题 感觉是产品经理方向 说B战有一个视频的播放量 一
  • java awt实现拖拉式文件路径获取

    package com example drag import java awt GridLayout import java awt datatransfer DataFlavor import java awt dnd DnDConst
  • SQL——根据字段包含值,统计条数(全文索引、CONTAINS、instr)

    根据字段包含值 统计条数 例如my column字段值可能为 0 1 2 3 4 5 目标 统计my column中的值为0 为1 为2 的各个条数 方式一 使用CONTAINS 该功能建立在全文索引之上 删除全文索引 DROP CONTE
  • 景联文科技高质量教育GPT题库:引领教育行业的技术革命

    ChatGPT拉开了大语言题库和生成式AI产业蓬勃发展的序幕 全世界教育科技公司扎堆接入GPT 4 涵盖美国 欧洲 日韩 中东和北非地区等 大语言题库在教育领域中势必将获得更加广阔的应用前景和丰富的应用场景 杭州景联文科技是AI基础数据行业
  • ElasticSearch text 和 keyword 类型

    ElasticSearch text 和 keyword 类型 text 会进行分词 先把对象进行分词处理 然后存入到es中 当使用多个单词进行查询的时候 查不到已经分词过的内容 keyword 不会进行分词 不会对es中的对象进行分词处理
  • FreeRTOS任务创建、删除

    目录 一 FreeRTOS任务创建与删除有关函数 1 1 创建 删除任务的API函数 1 1 1 动态创建任务 1 1 2 静态创建任务 1 1 3 删除任务 二 FreeRTOS任务创建与删除 动态方法 2 1 实例 三 FreeRTOS
  • LeetCode 沙漏的最大总和

    以最中间的的那个元素来移动 整个沙漏移动 class Solution public int maxSum int grid int max 0 int sum 0 for int i 1 i lt grid length 1 i for
  • 【华为OD机试】路灯照明问题【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 在一条笔直的公路上安装了N个路灯 从位置0开始安装 路灯之间间距固定为100米 每个路灯都有自己的照明半径 请计算第一个路灯和最后一个路灯之间 无法照明的区间的长度和
  • 线上git仓库地址更改,本地如何更改?

    1 进入终端查看本地代码关联的git仓库地址 git remote v 2 删除本地关联的git仓库地址 git remote rm origin 3 本地代码关联新的仓库地址 git remote add origin 新地址 4 再次查
  • 获取BDUSS的简单方式

    BDUSS是登录百度 web wap 后的唯一身份凭证 baidu com 受http only保护 拿到BDUSS就等于拿到帐号的控制权 通行贴吧 知道 百科 文库 空间 百度云等百度主要产品 在 贴吧云签系统 中 需要用到BDUSS进行
  • Linux下查看磁盘使用率及文件和文件夹大小

    原文地址 http blog sina com cn s blog 4ab088470106ge0o html 大家在使用linux的过程中 或许遇到过数据无法入库 无法上传数据等等 这就要多长个心眼 去查看一下磁盘使用率和文件大小吧 这时
  • 贪心+二分解决最大值最小、最小值最大问题

    在刷题时 总会遇到求最大值最小 最小值最大问题 也许它会暗喻是这样的一个问题 对于这样的一个问题 你会发现用dp和枚举都会超时超内存 或者说很麻烦 所以这是一个比较简单的解题方式 二分逼近思想 对于难以直接确定解的问题 采取二分枚举 检验的