목차
1 요구 사항
2 수요 분석
2.1 고정 빨간 봉투
2.2 무작위 빨간 봉투
3 요구 사항 디자인
3.1 클래스 다이어그램 디자인
3.2 소스 코드 디자인
3.3 결과 표시
백엔드 개발 PHP 튜토리얼 PHP가 고정된 빨간색 봉투와 임의의 빨간색 봉투 알고리즘을 구현하는 방법에 대한 자세한 설명(그림)

PHP가 고정된 빨간색 봉투와 임의의 빨간색 봉투 알고리즘을 구현하는 방법에 대한 자세한 설명(그림)

Jul 17, 2017 pm 03:47 PM
php 빨간 봉투

1 요구 사항

CleverCode는 최근 고정 빨간색 봉투 + 임의 빨간색 봉투 알고리즘을 작성해 달라는 요청을 받았습니다.

1 고정 빨간 봉투는 각 빨간 봉투의 양이 동일하다는 것을 의미합니다. 고정 빨간 봉투를 수량만큼 보낼 수 있습니다.

2 랜덤 빨간봉투에 대한 수요는 입니다. 예를 들어 빨간 봉투 총액이 5위안이면 빨간 봉투 10개를 보내야 합니다. 무작위 범위는 0.01~0.99이며, 5위안을 지불해야 하며 금액은 특정 추세를 갖는 정규 분포를 가져야 합니다. (0.99는 임의로 지정하거나 avg * 2 - 0.01일 수 있습니다. 예: avg = 5 / 10 = 0.5; (avg * 2 - 0.01 = 0.99))

2 수요 분석

2.1 고정 빨간 봉투

고정된 빨간 봉투라면 알고리즘은 직선입니다. t는 빨간 봉투의 고정된 양입니다. 그림과 같습니다.
f(x) = t; (1 <= x <= num)


2.2 무작위 빨간 봉투

무작위 함수 rand를 사용하면. rand(0.01,0.99); 그런 다음 무작위로 10번, 최악의 시나리오가 금액이 0.99인 경우 총 금액은 9.9위안입니다. 5 위안 이상이 될 것입니다. 금액도 정규 분포되지 않습니다. 마지막으로, 포물선과 삼각 함수를 사용할 수 있는 임의의 빨간색 봉투 생성기로 수학 함수를 사용하는 방법을 생각했습니다. 마지막으로 이등변 삼각 선형 함수가 선택되었습니다.

1 알고리즘 원리

보내려는 빨간 봉투의 총량을 totalMoney라고 하면, 빨간 봉투의 개수는 num, 금액 범위는 [min,max]이고 일차방정식은 그림과 같습니다.


세 점의 좌표:

(x1,y1) =  (1,min)
  (x2,y2)  = (num/2,max)
  (x3,y3) = (num,min)
로그인 후 복사

결정된 선형 방정식:

$y = 1.0 * ($x - $x1) / ($x2 - $x1) * ($y2 - $y1) + $y1 ; (x1 <= x <= x2)
$y = 1.0 * ($x - $x2) / ($x3 - $x2) * ($y3 - $y2) + $y2;  (x2 <= x <= x3)
로그인 후 복사

수정된 데이터:
y(전체) = y1 + y2 + y3 +...
y(전체)는 > totalMoney일 수 있습니다. , 생성된 양이 너무 많아서 데이터를 수정해야 함을 나타냅니다. 그런 다음 매번 (y1, y2, y3...ynum)에서 0.01씩 줄입니다. y(total) = totalMoney까지.
y (함께)는 < totalMoney일 수 있으며, 이는 생성된 금액이 적고 데이터를 수정해야 함을 나타내며 (y1, y2, y3...ynum)에서 매번 0.01을 추가합니다. y(total) = totalMoney까지.

2 알고리즘 원리의 예

발행할 빨간 봉투의 총량이 11470개이고, 빨간 봉투의 개수는 7400개이며, 금액 범위는 [0.01, 3.09]이면 일차방정식은 다음과 같습니다. 그림에서.


3 요구 사항 디자인

3.1 클래스 다이어그램 디자인


3.2 소스 코드 디자인

<?php
/**
 * 随机红包+固定红包算法[策略模式]
 * copyright (c) 2016 http://blog.csdn.net/CleverCode
 */

//配置传输数据DTO
class OptionDTO
{/*{{{*/

    //红包总金额
    public $totalMoney;

    //红包数量
    public $num;

    //范围开始
    public $rangeStart;

    //范围结算
    public $rangeEnd;

    //生成红包策略
    public $builderStrategy;

    //随机红包剩余规则
    public $randFormatType; //Can_Left:不修数据,可以有剩余;No_Left:不能有剩余

    public static function create($totalMoney,$num,$rangeStart,$rangEnd,
        $builderStrategy,$randFormatType = &#39;No_Left&#39;)
    {/*{{{*/
        $self = new self();
        $self->num = $num;
        $self->rangeStart = $rangeStart;
        $self->rangeEnd = $rangEnd;
        $self->totalMoney = $totalMoney;
        $self->builderStrategy = $builderStrategy;
        $self->randFormatType = $randFormatType;
        return $self; 
    }/*}}}*/

}/*}}}*/

//红包生成器接口
interface IBuilderStrategy
{/*{{{*/
    //创建红包
    public function create();    
    //设置配置
    public function setOption(OptionDTO $option); 
    //是否可以生成红包
    public function isCanBuilder();
    //生成红包函数
    public function fx($x);
}/*}}}*/

//固定等额红包策略
class EqualPackageStrategy implements IBuilderStrategy
{/*{{{*/
    //单个红包金额
    public $oneMoney;

    //数量
    public $num;

    public function construct($option = null) 
    {
        if($option instanceof OptionDTO)
        {
            $this->setOption($option);
        }
    }

    public function setOption(OptionDTO $option)
    {
        $this->oneMoney = $option->rangeStart;
        $this->num = $option->num;
    }

    public function create() 
    {/*{{{*/

        $data = array();
        if(false == $this->isCanBuilder())
        {
            return $data;    
        }

        $data = array();
        if(false == is_int($this->num) || $this->num <= 0) 
        {
            return $data;    
        }
        for($i = 1;$i <= $this->num;$i++)
        {
            $data[$i] = $this->fx($i);
        }
        return $data;
    }/*}}}*/
    
    /**
     * 等额红包的方程是一条直线 
     * 
     * @param mixed $x 
     * @access public
     * @return void
     */
    public function fx($x) 
    {/*{{{*/
        return $this->oneMoney; 
    }/*}}}*/

    /**
     * 是否能固定红包 
     * 
     * @access public
     * @return void
     */
    public function isCanBuilder()
    {/*{{{*/
        if(false == is_int($this->num) || $this->num <= 0) 
        {
            return false;    
        }

        if(false ==  is_numeric($this->oneMoney) || $this->oneMoney <= 0)
        {
            return false;
        }

        //单个红包小于1分
        if($this->oneMoney < 0.01)
        {
            return false;
        }
        
        return true;

    }/*}}}*/


}/*}}}*/

//随机红包策略(三角形)
class RandTrianglePackageStrategy implements IBuilderStrategy
{/*{{{*/
    //总额
    public $totalMoney;

    //红包数量
    public $num;

    //随机红包最小值
    public $minMoney;

    //随机红包最大值
    public $maxMoney;

    //修数据方式:NO_LEFT: 红包总额 = 预算总额;CAN_LEFT: 红包总额 <= 预算总额
    public $formatType; 

    //预算剩余金额
    public $leftMoney;


    public function construct($option = null) 
    {/*{{{*/
        if($option instanceof OptionDTO)
        {
            $this->setOption($option);
        }
    }/*}}}*/

    public function setOption(OptionDTO $option)
    {/*{{{*/
        $this->totalMoney = $option->totalMoney;
        $this->num = $option->num;
        $this->formatType = $option->randFormatType;
        $this->minMoney = $option->rangeStart;
        $this->maxMoney = $option->rangeEnd;
        $this->leftMoney = $this->totalMoney;
    }/*}}}*/

    /**
     * 创建随机红包 
     * 
     * @access public
     * @return void
     */
    public function create() 
    {/*{{{*/
        
        $data = array();
        if(false == $this->isCanBuilder())
        {
            return $data;    
        }
        
        $leftMoney = $this->leftMoney;
        for($i = 1;$i <= $this->num;$i++)
        {
            $data[$i] = $this->fx($i);
            $leftMoney = $leftMoney - $data[$i]; 
        }

        //修数据
        list($okLeftMoney,$okData) = $this->format($leftMoney,$data);

        //随机排序
        shuffle($okData);
        $this->leftMoney = $okLeftMoney;

        return $okData;
    }/*}}}*/

    /**
     * 是否能够发随机红包 
     * 
     * @access public
     * @return void
     */
    public function isCanBuilder()
    {/*{{{*/
        if(false == is_int($this->num) || $this->num <= 0) 
        {
            return false;    
        }

        if(false ==  is_numeric($this->totalMoney) || $this->totalMoney <= 0)
        {
            return false;
        }

        //均值
        $avgMoney = $this->totalMoney / 1.0 / $this->num;
        
        //均值小于最小值
        if($avgMoney < $this->minMoney )
        {
            return false;
        }
        
        return true;

    }/*}}}*/

    /**
     * 获取剩余金额 
     * 
     * @access public
     * @return void
     */
    public function getLeftMoney()
    {/*{{{*/
        return $this->leftMoney;
    }/*}}}*/

    /**
     * 随机红包生成函数。三角函数。[(1,0.01),($num/2,$avgMoney),($num,0.01)] 
     * 
     * @param mixed $x,1 <= $x <= $this->num; 
     * @access public
     * @return void
     */
    public function fx($x)
    {/*{{{*/
        
        if(false == $this->isCanBuilder())
        {
            return 0;
        }

        if($x < 1 || $x > $this->num)
        {
            return 0;
        }
        
        $x1 = 1;
        $y1 = $this->minMoney;
        
        //我的峰值
        $y2 = $this->maxMoney;

        //中间点
        $x2 = ceil($this->num /  1.0 / 2);

        //最后点
        $x3 = $this->num;
        $y3 = $this->minMoney;  

        //当x1,x2,x3都是1的时候(竖线)
        if($x1 == $x2 && $x2 == $x3)
        {
            return $y2;
        }

        // &#39;/_\&#39;三角形状的线性方程
        //&#39;/&#39;部分
        if($x1 != $x2 && $x >= $x1 && $x <= $x2)
        {

            $y = 1.0 * ($x - $x1) / ($x2 - $x1) * ($y2 - $y1) + $y1;  
            return number_format($y, 2, &#39;.&#39;, &#39;&#39;);
        }

        //&#39;\&#39;形状
        if($x2 != $x3 && $x >= $x2 && $x <= $x3)
        {

            $y = 1.0 * ($x - $x2) / ($x3 - $x2) * ($y3 - $y2) + $y2;  
            return number_format($y, 2, &#39;.&#39;, &#39;&#39;);
        }
        
        return 0;


    }/*}}}*/

    /**
     * 格式化修红包数据 
     * 
     * @param mixed $leftMoney 
     * @param array $data 
     * @access public
     * @return void
     */
    private function format($leftMoney,array $data)
    {/*{{{*/

        //不能发随机红包
        if(false == $this->isCanBuilder())
        {
            return array($leftMoney,$data);  
        }
        
        //红包剩余是0
        if(0 == $leftMoney)
        {
            return array($leftMoney,$data);  
        }

        //数组为空
        if(count($data) < 1)
        {
            return array($leftMoney,$data);  
        }

        //如果是可以有剩余,并且$leftMoney > 0
        if(&#39;Can_Left&#39; == $this->formatType
          && $leftMoney > 0)
        {
            return array($leftMoney,$data);  
        }


        //我的峰值
        $myMax = $this->maxMoney;

        // 如果还有余钱,则尝试加到小红包里,如果加不进去,则尝试下一个。
        while($leftMoney > 0)
        {
            $found = 0;
            foreach($data as $key => $val) 
            {
                //减少循环优化
                if($leftMoney <= 0)
                {
                    break;
                }

                //预判
                $afterLeftMoney =  (double)$leftMoney - 0.01;
                $afterVal = (double)$val + 0.01;
                if( $afterLeftMoney >= 0  && $afterVal <= $myMax)
                {
                    $found = 1;
                    $data[$key] = number_format($afterVal,2,&#39;.&#39;,&#39;&#39;);
                    $leftMoney = $afterLeftMoney;
                    //精度
                    $leftMoney = number_format($leftMoney,2,&#39;.&#39;,&#39;&#39;);
                }
            }

            //如果没有可以加的红包,需要结束,否则死循环
            if($found == 0)
            {
                break;
            }
        }
        //如果$leftMoney < 0 ,说明生成的红包超过预算了,需要减少部分红包金额
        while($leftMoney < 0)
        {
            $found = 0;
            foreach($data as $key => $val) 
            {
                if($leftMoney >= 0)
                {
                    break; 
                }
                //预判
                
                $afterLeftMoney =  (double)$leftMoney + 0.01;
                $afterVal = (double)$val - 0.01;
                if( $afterLeftMoney <= 0 && $afterVal >= $this->minMoney)
                {
                    $found = 1;
                    $data[$key] = number_format($afterVal,2,&#39;.&#39;,&#39;&#39;);
                    $leftMoney = $afterLeftMoney;
                    $leftMoney = number_format($leftMoney,2,&#39;.&#39;,&#39;&#39;);
                }
            }
            
            //如果一个减少的红包都没有的话,需要结束,否则死循环
            if($found == 0)
            {
                break;
            }
        }
        return array($leftMoney,$data);  
    }/*}}}*/

}/*}}}*/

//维护策略的环境类
class RedPackageBuilder
{/*{{{*/

    // 实例  
    protected static $_instance = null;  

    /** 
     * Singleton instance(获取自己的实例) 
     * 
     * @return MemcacheOperate 
     */  
    public static function getInstance()
    {  /*{{{*/
        if (null === self::$_instance) 
        {  
            self::$_instance = new self();  
        }  
        return self::$_instance;  
    }  /*}}}*/

    /** 
     * 获取策略【使用反射】
     * 
     * @param string $type 类型 
     * @return void 
     */  
    public function getBuilderStrategy($type)
    {  /*{{{*/
        $class = $type.&#39;PackageStrategy&#39;;

        if(class_exists($class))
        {
            return new $class();  
        }
        else
        {
            throw new Exception("{$class} 类不存在!");
        }
    }  /*}}}*/

    public function getRedPackageByDTO(OptionDTO $optionDTO) 
    {/*{{{*/
        //获取策略
        $builderStrategy = $this->getBuilderStrategy($optionDTO->builderStrategy);

        //设置参数
        $builderStrategy->setOption($optionDTO);

        return $builderStrategy->create();
    }/*}}}*/
    
}/*}}}*/

class Client
{/*{{{*/
    public static function main($argv)
    {
        //固定红包
        $dto = OptionDTO::create(1000,10,100,100,&#39;Equal&#39;);
        $data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
        //print_r($data);

        //随机红包[修数据]
        $dto = OptionDTO::create(5,10,0.01,0.99,&#39;RandTriangle&#39;);
        $data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
        print_r($data);

        //随机红包[不修数据]
        $dto = OptionDTO::create(5,10,0.01,0.99,&#39;RandTriangle&#39;,&#39;Can_Left&#39;);
        $data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
        //print_r($data);
        
    }
}/*}}}*/

Client::main($argv);
로그인 후 복사

3.3 결과 표시

1 고정 빨간 봉투

//固定红包
$dto = OptionDTO::create(1000,10,100,100,&#39;Equal&#39;);
$data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
print_r($data);
로그인 후 복사


2 무작위 빨간색 봉투( 데이터 수정)

여기에서는 PHP의 무작위 정렬 기능인 shuffle($okData)이 사용되므로 표시되는 결과는 선형이 아니며 이 결과는 더 무작위입니다.

//随机红包[修数据]
 $dto = OptionDTO::create(5,10,0.01,0.99,&#39;RandTriangle&#39;);
 $data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
 print_r($data);
로그인 후 복사


3개의 무작위 빨간색 봉투(데이터 수정 없음)

데이터 수정 없음, 양은 1이고 num은 최소값 0.01입니다.

//随机红包[不修数据]
 $dto = OptionDTO::create(5,10,0.01,0.99,&#39;RandTriangle&#39;,&#39;Can_Left&#39;);
 $data = RedPackageBuilder::getInstance()->getRedPackageByDTO($dto);
 print_r($data);
로그인 후 복사



위 내용은 PHP가 고정된 빨간색 봉투와 임의의 빨간색 봉투 알고리즘을 구현하는 방법에 대한 자세한 설명(그림)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

CakePHP 프로젝트 구성 CakePHP 프로젝트 구성 Sep 10, 2024 pm 05:25 PM

이번 장에서는 CakePHP의 환경 변수, 일반 구성, 데이터베이스 구성, 이메일 구성에 대해 알아봅니다.

Ubuntu 및 Debian용 PHP 8.4 설치 및 업그레이드 가이드 Ubuntu 및 Debian용 PHP 8.4 설치 및 업그레이드 가이드 Dec 24, 2024 pm 04:42 PM

PHP 8.4는 상당한 양의 기능 중단 및 제거를 통해 몇 가지 새로운 기능, 보안 개선 및 성능 개선을 제공합니다. 이 가이드에서는 Ubuntu, Debian 또는 해당 파생 제품에서 PHP 8.4를 설치하거나 PHP 8.4로 업그레이드하는 방법을 설명합니다.

CakePHP 날짜 및 시간 CakePHP 날짜 및 시간 Sep 10, 2024 pm 05:27 PM

cakephp4에서 날짜와 시간을 다루기 위해 사용 가능한 FrozenTime 클래스를 활용하겠습니다.

CakePHP 파일 업로드 CakePHP 파일 업로드 Sep 10, 2024 pm 05:27 PM

파일 업로드 작업을 위해 양식 도우미를 사용할 것입니다. 다음은 파일 업로드의 예입니다.

CakePHP 라우팅 CakePHP 라우팅 Sep 10, 2024 pm 05:25 PM

이번 장에서는 라우팅과 관련된 다음과 같은 주제를 학습하겠습니다.

CakePHP 토론 CakePHP 토론 Sep 10, 2024 pm 05:28 PM

CakePHP는 PHP용 오픈 소스 프레임워크입니다. 이는 애플리케이션을 훨씬 쉽게 개발, 배포 및 유지 관리할 수 있도록 하기 위한 것입니다. CakePHP는 강력하고 이해하기 쉬운 MVC와 유사한 아키텍처를 기반으로 합니다. 모델, 뷰 및 컨트롤러 gu

PHP 개발을 위해 Visual Studio Code(VS Code)를 설정하는 방법 PHP 개발을 위해 Visual Studio Code(VS Code)를 설정하는 방법 Dec 20, 2024 am 11:31 AM

VS Code라고도 알려진 Visual Studio Code는 모든 주요 운영 체제에서 사용할 수 있는 무료 소스 코드 편집기 또는 통합 개발 환경(IDE)입니다. 다양한 프로그래밍 언어에 대한 대규모 확장 모음을 통해 VS Code는

CakePHP 유효성 검사기 만들기 CakePHP 유효성 검사기 만들기 Sep 10, 2024 pm 05:26 PM

컨트롤러에 다음 두 줄을 추가하면 유효성 검사기를 만들 수 있습니다.

See all articles