常规解法
常规思路需要 O(n*n) 的时间复杂度 才能计算出来
具体做法就是 穷举,从 0-n 不停的作为出发点测试
基于常规进行优化
模拟常规代码
for i~ n { can[i] = 0 for j=i;j<i+n;j++ { j = j %n sum += oil[j] - dis[j] if sum < 0 { break } } if j == i+n { can[i] = 1 } }
我们发现 其实我们在反复探测从不同出发点是否能够走通,走通就标记一下,其实我们中间有好多次重复的计算,比如 以下标0 为起点,需要计算 0-n ,从下标1触发需要计算 1-n -0 中间绝大部分都是重复的,如何解?
因为每一次的起点是不同的,所以我们需要对起点之后每一站从新计算,才能算准油量是否足够。反过来想,如果我们将一个点作为出发点,当油量不够的时候,直接“回朔” 加上起点之前的节点的油量是否就可以规避反复的计算,但是此时,这个循环的意义会缩减为 “寻找一个点A,从这个点出发一定能到完全程?”
我们得到了点A,同样的思维,我们从点A出发,如果一个点剩余静里程大于0 ,则上个点一定也能走完全程,接着想上一个点探测,如果小于0呢!则这个节点就要暂时放弃,累加/回朔上节点的上一个节点,继续探测。
完整代码
package main import ( "fmt" "os" "bufio" "strconv" ) func main(){ var n int fmt.Scanf("%d",&n) scanner := bufio.NewScanner(os.Stdin) scanner.Split(bufio.ScanWords) oil := make([]int,n) dis := make([]int,n) for i:=0;i<n;i++{ if scanner.Scan(){ oil[i],_ = strconv.Atoi(scanner.Text()) } } for i:=0;i<n;i++{ if scanner.Scan(){ dis[i],_ = strconv.Atoi(scanner.Text()) } } helper(oil,dis,n) return } func helper(oil,dis []int,n int){ //计算某个位置的静里程数 for i:=0;i<n;i++{ oil[i] -= dis[i] dis[i] = -1 } start := 0 end := 1 ans := 0 //第一遍查找,确定是否可以走通 for start != end { if ans>=0{ ans += oil[end] end = (end +1) % n }else{ ans += oil[start] start = (start-1+n) %n } } //排除不合规的条件 if ans < 0 { for i:=0;i<n;i++{ fmt.Printf("%d ",0) } return } //至此,从一个可以走通的地方不停的倒序探索,直到探索完 cur := start; ans = oil[start] for dis[cur] == -1 { //可达,探索上一个位置 if ans >=0 { dis[cur] = 1 cur = (cur -1 +n) %n ans = oil[cur] }else{ //不可达 累加上一个位置并探索 dis[cur] = 0 cur = (cur-1+n) %n ans += oil[cur] } } //输出结果 for i:=0;i<n;i++{ fmt.Printf("%d ",dis[i]) } return }