[算法学习] 三分

三分的用途

二分可以用来求解单调函数,三分可以用来求单峰/单谷函数的极值,当我们确定了某个单峰\单谷的函数表达式,就可以在O(log3n)的复杂度求出该函数的极值。

三分的原理

和二分类似,二分是将区间分为两半,每次根据mid的取值判断应该删除哪一个区间。三分则是将区间分成三部分,[l,mid1],[mid1,mid2],[mid2,r],每次根据mid1和mid2的取值来确定舍弃一个区间,从而不断缩小极值的取值范围。
例如求一个二次函数的极值,我们将区间等分为3份,如果f(m1)<f(m2),说明m2更靠近极值点,我们舍弃[l,m1]这个区间,反之舍弃[m2,r],最终就能求出该函数的极值
在这里插入图片描述

三分的模板

 while (r - l > eps)
    {
        double mid = (r - l) / 3.0;
        double m1 = l + mid;
        double m2 = m1 + mid;

        if (f(m1) < f(m2))
            l = m1;
        else
            r = m2;
    }

例题

2020icpc南京站F-fireworks
在这里插入图片描述
在这里插入图片描述
题目大意:
制作一个烟花需要n时间,燃放所有烟花需要m时间,做出一个能燃放的烟花的概率是p,问使用最佳策略制作和燃放烟花,能够成功释放烟花的最小时间的期望是多少。
思路:
设每做k个烟花释放为最佳策略,则实验符合几何分布,成功释放烟花的概率为1-(1-p)k,E(k)=(n*k+m)/(1-(1-p)k),求导后发现E(k)有一个零点,是单峰函数,对其三分求极小值即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,m;
long double p;
long double f(long double x)  
{
    return ((long double)x*n+m)/((long double)1.0-pow((1.0-p),x));
}

int main()
{
	int t;
	cin>>t;
	while(t--)
	{
		cin>>n>>m>>p;
		int l=0,r=1e9+10;
		p*=1e-4;
		while(r-l>=1)
		{
			int m1 = l+(r-l)/3;
			int m2 = r-(r-l)/3;
			if(f(m1)<f(m2))
				r=m2-1;
			else l=m1+1;
		}
		//cout<<l<<endl;
		printf("%.15Lf\n",f(l));
	}
	
	return 0;
}
  • 9
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中提到了一种简单的实现三分频的方法,即通过计数器来实现。具体步骤是: 1. 使用一个计数器来进行模三计数,即每当计数器计数到三的倍数时,输出时钟翻转一次。 2. 当计数器计数到2的时候,再翻转一次输出时钟。 下面是对应的三分频verilog代码和相应的testbench代码: ```verilog // 三分频模块 module DivideBy3( input wire clk_in, // 输入时钟 output wire clk_out // 输出时钟 ); reg [1:0] count; // 计数器,2位二进制数 always @(posedge clk_in) begin if (count == 2) begin count <= 0; clk_out <= ~clk_out; end else begin count <= count + 1; end end endmodule // 三分频测试模块 module DivideBy3Testbench; reg clk_in; // 输入时钟 wire clk_out; // 输出时钟 // 实例化三分频模块 DivideBy3 divideBy3( .clk_in(clk_in), .clk_out(clk_out) ); // 输入时钟信号 always begin #5 clk_in = ~clk_in; end endmodule ``` 这个代码实现了一个简单的三分频模块,并且还提供了一个测试模块进行验证。在测试模块中,输入时钟信号每过5个时间单位就翻转一次,然后通过实例化的三分频模块将输入时钟进行分频,得到输出时钟信号。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [verilog二分频代码&verilog三分频代码](https://blog.csdn.net/supenman_mwg/article/details/7654141)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [3分频器 verilog解析](https://blog.csdn.net/andersonanya/article/details/52662745)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值