[编程题]击败魔物 小红书 二分查找

[编程题]击败魔物 小红书 二分查找

我们把问题分解成两个子问题:

1.已知 必杀技伤害X 验证能否获胜
2.二分查找能够获胜的最小伤害X

考虑二分查找的上下边界:

  • 平A即可取胜,此时为X的下界0
  • 技能秒杀任意怪,此时为X的上界为怪物的最大血量,伤害更高没有意义
package main
 
import (
    "fmt"
    "sort"
)

//求和
func sum(arr []int) (ans int) {
    for _,v:=range arr{
        ans+=v
    }
    return
}

//求较小值
func min(i,j int) int {
    if i<j{
        return i
    }else{
        return j
    }
}
 
//验证能否获胜
func f(ohs []int,n,t,m,x int) bool {
    hs:=make([]int, len(ohs))
    copy(hs,ohs)
    for i,v:=range hs{
         d:=min(v/x,m)
         hs[i]-=d*x
         m-=d
         t-=d
         if m==0{
            break
         }
    }
    sort.Ints(hs)
    i:=0
    for ;hs[i]==0;i++{}
    hs=hs[i:]
    if len(hs)==0{
        return true
    }
    n= len(hs)
    if n<=m{
        return true
    }else{
        hs=hs[:n-m]
        t-=m
        return t>=sum(hs)
    }
}

func main() {
    var n,t,m,h int
 	
 	//回合数小于怪物数,必失败
    if t<n{
        fmt.Println(-1)
        return
    }
 
 	//法力值大于回合数时多的也没用
    if m>t{
        m=t
    }
    
 	//获取怪物血量
    var hs []int
    fmt.Scan(&n,&t,&m)
    for i:=0;i<n;i++{
        fmt.Scan(&h)
        hs = append(hs, h)
    }
 
 	//平A取胜
    if t>sum(hs){
        fmt.Println(0)
        return
    }
    
    sort.Ints(hs)
    
    //二分查找
    l,r:=0,hs[len(hs)-1]
    if !f(hs,n,t,m,r){
        fmt.Println(-1)
        return
    }
    for l<r-1{
        mid:=(l+r)/2
        if f(hs,n,t,m,mid){
            r=mid
        }else{
            l=mid
        }
    }
    fmt.Println(r)
}

你可能感兴趣的:(算法)