一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第21天,点击查看活动详情。
原题地址
题目大意
由于原题介绍很冗长,所以这里简单化一下:
小明和小红玩游戏,掷硬币,规则是这样的,硬币有正反面,掷到正面就加一分,反面不加分。
一共十把,第一把小明掷,第二把小红掷,第三把小明掷,第四把小红掷,,,,,,
第九把小明掷,第十把小红掷。
如此这般,最后看谁的分数多,谁就胜利。
谁胜利不重要,我们要解决的问题是,到第几把结束之后,就不用接着玩了,因为结局已经注定是小明或者小红赢了。
什么意思,比如说,第七把小明掷玩之后,此时小明如果积分是1,小红是3。
后面小明还能掷一次,怎么样也不能反超了,所以比赛可以终止了,八,九,十这三把无需再掷。
题目还没完,现在假设你有一种预知未来的能力,对于这十把游戏来说,你能大概给出一个预测,比如说:
1101?11011
上面十个字符代表你对每一把的预测:
- 数字
1代表,本次相应玩家获得一分 - 数字
0代表,本次相应玩家获得0分 - 字符
?代表,本次无法预知
看上面的例子,除了第五把无法预知,其他的都是明确预知的。
问题来了:在给定十个预测结果的情况下,最少玩几把,就可以宣布比赛终止(因为结果无法逆转了)?
解题思路
由于对于?的理解可能出错,我们来讲解一个例子:
??????????
就是这种,也就是说,你完全无法预知。
不要认为,此时就一定会打完十场。
题目意思是,最少打几场,就是说,只要可能发生的就行。
也就是说,你可以认为?就是随意填写,你可以填0,也可以填1,然后穷举所有情况,找到那个最小的就行。
第一种方法:穷举法
正如上面说的,将里面的?的所有可能性全都穷举一遍,然后看看哪一种,能在最少比赛次数就能终止游戏。
由于穷举法,不好,所以不给代码了。
优化之后
这里基于一个简单的逻辑:
两者分数相差越大,那么就越提前终止比赛。
那么就简单了:
- 让所有
?,都向着小明赢的方向走 - 让所有
?,都向着小红赢的方向走
然后看看上面两种,哪种会让比赛更早结束,即可!
下面给代码(Golang):
func minTime(s string) int {
var res = 9
//尽量让小明赢:
{
var score0, score1 int
for loop := 0; loop < 10; loop++ {
if loop%2 == 0 {
if s[loop] != '0' {
score0++
}
} else {
if s[loop] == '1' {
score1++
}
}
if score0 > score1+(10-loop)/2 { // 如果小明已经赢了
res = min(res, loop)
}
if score1 > score0+(9-loop)/2 { // 如果小红已经赢了
res = min(res, loop)
}
}
}
//尽量让小红赢:
{
var score0, score1 int
for loop := 0; loop < 10; loop++ {
if loop%2 == 0 {
if s[loop] == '1' {
score0++
}
} else {
if s[loop] != '0' {
score1++
}
}
if score0 > score1+(10-loop)/2 { // 如果小明已经赢了
res = min(res, loop)
}
if score1 > score0+(9-loop)/2 { // 如果小红已经赢了
res = min(res, loop)
}
}
}
return res + 1
}
func min(a, b int) int {
if a < b {
return a
}
return b
}
注意,上面两个代码块,是尽量让某某赢,但是不能保证某某赢,所以要在最后判断的时候,两种可能性都判断一下才行。