T2-达到目标的最小操作次数![在这里插入图片描述](https://i-blog.csdnimg.cn/blog_migrate/80feb55364b73b7787f0a9e8d2d184b7.png)
-
intution:要充分利用加倍,必须在数尽量大时加倍。
- 如果target是奇数,则最后一步一定是递增1.
- 如果target是偶数,则最后一步是什么?
贪心选择
- 一定存在一种最优解,在target是偶数时,最后一步的操作是加倍。
- 证明:如果所有的最优解最后一步都不是加倍。任取一个最优解,最后一步加倍在小于target/2的数上进行,设为 k k k。即将 k k k加倍到 2 k 2k 2k后再将其递增到target。从k开始,这个最优解的操作次数为:将k加倍到2k,从2k递增到target,总操作次数target - 2k + 1;而如果直接将k先递增到 t a r g e t / 2 target/2 target/2,再将其翻倍,总操作次数 t a r g e t / 2 − k + 1 target / 2 - k + 1 target/2−k+1,显然得到了一个更有的解,矛盾。
最优子结构(显然)
递归算法
class Solution {
public int minMoves(int target, int maxDoubles) {
if(target == 1)
return 0;
if(maxDoubles == 0)
return target - 1;
if(target % 2 == 0)
return minMoves(target / 2,maxDoubles - 1) + 1;
else return minMoves((target - 1)/2,maxDoubles - 1) + 2;
}
}
T4-同时运行 N 台电脑的最长时间
二分
- 前面周赛遇到过类似的题。确定可能的解空间后,使用二分查找找到最优解。
- 但问题的关键在于:给定一个时间,判断电脑是否能同时运行如此之长?关键在于形式化。
- 使用矩阵处理(想不到)。给定待判时间
k
k
k,电脑数目
n
n
n,设矩阵
A
∈
R
k
n
A \in R^{kn}
A∈Rkn,
A
i
j
A_{ij}
Aij表示第i分钟电脑j使用电池
A
i
j
A_{ij}
Aij,
A
i
j
∈
[
0
,
m
−
1
]
A_{ij} \in [0,m-1]
Aij∈[0,m−1]为电池编号,A是合法矩阵的充分必要条件是(也就是k是一个可行解)
- 矩阵A的每一行元素互不相同
- ∀ x ∈ [ 0 , m − 1 ] \forall x \in [0,m-1] ∀x∈[0,m−1],其在A中出现的次数小于等于 b a t t e r y [ x ] battery[x] battery[x]
设: o c c ( x ) = m i n { k , b a t t e r y [ x ] } occ(x) =min\{k,battery[x]\} occ(x)=min{k,battery[x]}若A合法,则x在矩阵A中出现的次数小于等于occ(x)
- 命题:
A
A
A是合法矩阵的充要条件是
∑
x
=
0
m
−
1
o
c
c
(
x
)
≥
k
⋅
n
\sum_{x = 0}^{m-1} occ(x) \geq k \cdot n
x=0∑m−1occ(x)≥k⋅n
- 如果A合法, ∑ x ∈ A o c c ( x ) ≥ k ⋅ n \sum_{x \in A} occ(x) \geq k \cdot n ∑x∈Aocc(x)≥k⋅n,而 ∑ x = 0 m − 1 o c c ( x ) ≥ ∑ x ∈ A o c c ( x ) ≥ k ⋅ n \sum_{x = 0}^{m-1} occ(x) \geq \sum_{x \in A} occ(x) \geq k \cdot n ∑x=0m−1occ(x)≥∑x∈Aocc(x)≥k⋅n,即证。
- 反之,如果 ∑ x = 0 m − 1 o c c ( x ) ≥ k ⋅ n \sum_{x = 0}^{m-1} occ(x) \geq k \cdot n ∑x=0m−1occ(x)≥k⋅n, 对于每个x,将其填入A的不同行中occ(x)次。对于每个x重复直到将A填满。由occ(x)的定义,A是合法的。
- 于是对于给定的k,只需判断 ∑ x = 0 m − 1 o c c ( x ) ≥ k ⋅ n \sum_{x = 0}^{m-1} occ(x) \geq k \cdot n ∑x=0m−1occ(x)≥k⋅n是否成立,即可确定k是否是可行解。确定Binary Search的上界为 ⌊ ∑ i b a t t e r y [ i ] / n ⌋ \lfloor \sum_i battery[i] / n \rfloor ⌊∑ibattery[i]/n⌋,下界为0,搜索最后一个满足条件的k值。采用先前总结的二分查找框架实现:
class Solution {
public long maxRunTime(int n, int[] batteries) {
long high = 0;
for(int i : batteries)
high += (long)i;
high/=n;
long low = 1;
high++;
while(low < high)
{
long mid = low + ((high - low) >> 1);
long check = 0;
for(int i : batteries)
check += Math.min((long)i,mid);
if(check >= mid * n)
low = mid + 1;
else high = mid;
}
return low - 1;
}
}