任何人都可以提供正确的算法来解决这个问题。不是代码只是算法。谢谢。
你有N本书。每本ith书都有Pi页数。 您必须为M个学生分配书籍,以便最大限度地分配给学生的最大页数。一本书将分配给一名学生。每个学生必须至少分配一本书。
注意:如果无法进行有效的分配,则返回-1,并且分配应该是连续的顺序。
这是问题陈述的a link。
答案 0 :(得分:6)
将每个学生的最大值设置为X页。
要检查这是否可行,只需开始为第一个学生分配书籍,直到下一本书超过阈值X.然后切换到下一个等等(这是有效的,因为他们说分配需要是连续的)。
如果你的书用完了,那么这是可行的(你总是可以回去给学生更少的书来阅读以适应其他学生)。如果你的学生用完了,那就不行了。
此检查将为O(N),其中N是书籍数量。
现在你有了这个,做二进制搜索X. Complexity是O(NlogM),其中N是书籍数,M是总页数。
答案 1 :(得分:3)
好的,我将解释上述帖子中@Sorin的含义。
我们的基本方法设定了一个上限,然后检查我们是否可以根据这个上限为学生分配书籍,即。检查如果真的可以分配?
对于eg-Say我们有12,67,34,90作为我们的四本书,它们的值表示该书中的页数。假设我们的学生人数是2。 并且说我将上限设置为20(假设)。 现在让我们开始为学生分配书籍。
好的,现在剩下的就是如何找到这个上限。
答案 - 二进制搜索。
说明 -
检查上述算法的上限。
一个。如果基于算法接受此值。设r = mid-1(即检查它是否适用于较小的限制)。
湾如果不接受此值,则设置l = mid + 1(即检查它是否在更高的限制下工作)。
3.直到l<河
(注) - 最初检查(学生人数>图书)是否返回-1;
答案 2 :(得分:1)
这是二元搜索的经典例子答案。 所以你需要做一个观察: 如果增加学生人数(M),则要分配的最大页数(P_max)会减少。 当M = N时,将发生P_max(lo)的最小值。答案是所有P_i的最大值。 当M = 1时,将发生P_max(hi)的最大值。答案是所有P_i的总和。
现在,我们定义一个函数F(x),如果我们可以为每个学生分配最多x个页面并且仍然满足最多M个学生,则该函数将返回true。
如果我们可以从第一本书开始分配x页的连续总和,则可以通过遍历页数组(P)并将学生数增加1来计算F(x)。让我们将F(x)称为allocateBooks函数。 参数为页数组(P),书数(n),最大页数(x)和学生数(m)。
bool allocateBooks(int64_t P[], int64_t n, int64_t x, int64_t m){
int64_t sum = 0, count = 1;
for(int64_t i = 0; i < n; i ++){
sum += P[i];
if(sum > x){
count ++;
sum = P[i];
}
}
return (count <= m);
}
观察,对于特定情况:F(lo)=假,F(lo + 1)=假,...,F(lo + k)=假,F(lo + k + 1)=真,。 。,和F(hi)=真。
所以,我们可以看到它本质上是单调的。
在这种情况下,我们要找到第一个真值,(lo + k + 1)。二进制搜索救援。
int main() {
int64_t n;
cin >> n;
int64_t P[n], sum = 0, maxval = 0;
for(int64_t i = 0; i < n; i ++){
cin >> P[i];
sum += P[i];
maxval = max(maxval, P[i]);
}
int64_t m;
cin >> m;
// find the minimum of max pages in books
// Observation : when m = 1, ans = sum; while when m = n, ans = maxval
// Thus when m increases ans decreases
int64_t lo = maxval, hi = sum, mid;
while(hi > lo) {
mid = lo + (hi - lo) / 2;
if(allocateBooks(P, n, mid, m)){
hi = mid;
} else {
lo = mid + 1;
}
}
cout << hi << "\n";
return 0;
}