圆圈上有<LinearLayout
android:gravity="center"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<CheckBox
android:text="Some bla blablablablablablabla bla bla bla bla bla bla "
android:layout_width="0dp"
android:layout_weight="0.7"
android:layout_height="wrap_content" />
<Button
android:text="Button"
android:layout_width="0dp"
android:layout_weight="0.3"
android:layout_height="wrap_content" />
</LinearLayout>
个点,表示宝藏的位置。 K
人想分享宝藏。您希望将宝藏公平地分配在所有宝藏中,以使具有最大值的人和具有最小值的人之间的差异尽可能小。
例如,如图所示,如果有4件宝物和2个人,那么最佳的分割方式将是
(6,10)和(11,3)=>相差2。
1 <= n <= 25
1 <= k <= 50
我该如何解决这个问题?我计划计算所有点的均值,并继续添加资源,直到它们小于每个人的均值。但是,尽管很明显,它并非在所有情况下都有效。
如果有人扔光我会很高兴的。
答案 0 :(得分:1)
因此,说我们将x,y固定为宝藏允许的最小最大值。 我需要弄清楚我们是否可以在这些约束条件下找到解决方案。
为此,我需要遍历圆并创建x和y之和的正N个分段。 我可以通过动态编程解决a [i] [j] [l] = 1的问题,前提是我可以将i和j之间的元素拆分为l,它们的和在x和y之间(请参见上文)。为了计算它,我们可以评估a [i] [j] [l] = is_there_a_q_such_that(a [i] [q-1] [l-1] == 1且sum(q-> j)在x和y之间)。 要处理该圆,请寻找覆盖足够元素的n-1个段,其余的差值仍在x和y之间。
因此,天真的解决方案是O(total_sum ^ 2)选择X和Y加O(K ^ 3)遍历i,j,l和另一个O(K)来找到aq和另一个O(K)来获得总和。总数为O(total_sum ^ 2 * K ^ 5),可能太慢了。
因此,我们需要计算很多总和。因此,让我们预先计算部分和数组sums [w] = sum(pos 0和pos w之间的元素)。因此,要获得q和j之间的总和,只需计算sums [j]-sums [q-1]。这会照顾到O(K)。
计算a [i] [j] [l]。 由于珍宝始终是正数,因此如果部分总和过小,则需要增加间隔,如果总和过高,则需要缩小间隔。正弦,我们固定间隔的一侧(在j处),我们只能移动q。我们可以使用二进制搜索来找到闭合t和最远的q,使我们位于x和y之间。我们称它们为low_q(最接近j,最小和)和high_q(远离j,最大和)。如果low_q
我们前面仍然有total_sum ^ 2。假设我们修复了X。如果对于给定的y,我们有一个解决方案,那么您也许还能找到一个较小的y,但它仍然有一个解决方案。如果找不到给定y的解决方案,那么将找不到较小值的解决方案。现在我们可以对y进行二进制搜索。
所以现在是O(total_sum * log(total_sum)* K ^ 3 * logK)。
如果sum(0-> i-1)> x,其他优化将不加i。 您可能不想检查x> total_sum / K的值,因为这是理想的最小值。这应该消除K之一就是复杂性。
您可能还可以做其他事情,但是我认为这对于您的约束来说足够快了。
答案 1 :(得分:0)
您可以对O(k ^ n)进行蛮力操作,或者对O(k ^ {2} * MAXSUM ^ {k — 1})进行dp操作。
dp [i] [val1] [val2] ... [val k -1]有可能分配前k个项目,因此第一个具有val1,第二个具有val2,依此类推。有k * MAXSUM(k-1)个状态,您需要O(k)才能执行步骤,您只需选择谁选择第i个项目即可。
我认为不可能更快地解决它。
答案 2 :(得分:0)
不存在针对此问题的标准算法类型(贪婪,除法和征服等)。
您将必须检查(resource, people)
的每个组合并选择答案。使用递归解决问题后,可以抛出DP
来优化解决方案。
解决方案的重点是:
Recuse through all the treasures
If you current treasure is not the last,
set minimum difference to Infinity
for each user
assign the current treasure to the current user
ans = recurse further by going to the next treasure
update minimumDifference if necessary
else
Find and max amount of treasure assigned and minimum amount of treasure assigned
and return the difference
这是答案的JavaScript版本。
我评论了它也试图解释逻辑:
// value of the treasure
const K = [6, 3, 11, 10];
// number of users
const N = 2;
// Array which track amount of treasure with each user
const U = new Array(N).fill(0);
// 2D array to save whole solution
const bitset = [...new Array(N)].map(() => [...new Array(K.length)]);
const solve = index => {
/**
* The base case:
* We are out of treasure.
* So far, the assigned treasures will be in U array
*/
if (index >= K.length) {
/**
* Take the maximum and minimum and return the difference along with the bitset
*/
const max = Math.max(...U);
const min = Math.min(...U);
const answer = { min: max - min, set: bitset };
return answer;
}
/**
* We have treasures to check
*/
let answer = { min: Infinity, set: undefined };
for (let i = 0; i < N; i++) {
// Let ith user take the treasure
U[i] += K[index];
bitset[i][index] = 1;
/**
* Let us recuse and see what will be the answer if ith user has treasure at `index`
* Note that ith user might also have other treasures for indices > `index`
*/
const nextAnswer = solve(index + 1);
/**
* Did we do better?
* Was the difference bw the distribution of treasure reduced?
* If so, let us update the current answer
* If not, we can assign treasure at `index` to next user (i + 1) and see if we did any better or not
*/
if (nextAnswer.min <= answer.min) {
answer = JSON.parse(JSON.stringify(nextAnswer));
}
/**
* Had we done any better,the changes might already be recorded in the answer.
* Because we are going to try and assign this treasure to the next user,
* Let us remove it from the current user before iterating further
*/
U[i] -= K[index];
bitset[i][index] = 0;
}
return answer;
};
const ans = solve(0);
console.log("Difference: ", ans.min);
console.log("Treasure: [", K.join(", "), "]");
console.log();
ans.set.forEach((x, i) => console.log("User: ", i + 1, " [", x.join(", "), "]"));
索引为
i
的每个问题都会精确地创建N
的副本 本身,而我们总共有K
个索引,则问题的时间复杂度 要解决的是O(K^N)
我们绝对可以通过添加备忘录来做得更好。
这是棘手的部分:
如果我们为一个用户分配了财宝,则最低 用户之间的财富分配差异将是 一样。
在极端情况下,bitset[i]
代表ith
用户的分布。
因此,我们可以记住用户bitset
的结果。
您意识到这一点,编码很简单:
// value of the treasure
const K = [6, 3, 11, 10, 1];
// number of users
const N = 2;
// Array which track amount of treasure with each user
const U = new Array(N).fill(0);
// 2D array to save whole solution
const bitset = [...new Array(N)].map(() => [...new Array(K.length).fill(0)]);
const cache = {};
const solve = (index, userIndex) => {
/**
* Do we have cached answer?
*/
if (cache[bitset[userIndex]]) {
return cache[bitset[userIndex]];
}
/**
* The base case:
* We are out of treasure.
* So far, the assigned treasures will be in U array
*/
if (index >= K.length) {
/**
* Take the maximum and minimum and return the difference along with the bitset
*/
const max = Math.max(...U);
const min = Math.min(...U);
const answer = { min: max - min, set: bitset };
// cache the answer
cache[bitset[userIndex]] = answer;
return answer;
}
/**
* We have treasures to check
*/
let answer = { min: Infinity, set: undefined };
// Help us track the index of the user with optimal answer
let minIndex = undefined;
for (let i = 0; i < N; i++) {
// Let ith user take the treasure
U[i] += K[index];
bitset[i][index] = 1;
/**
* Let us recuse and see what will be the answer if ith user has treasure at `index`
* Note that ith user might also have other treasures for indices > `index`
*/
const nextAnswer = solve(index + 1, i);
/**
* Did we do better?
* Was the difference bw the distribution of treasure reduced?
* If so, let us update the current answer
* If not, we can assign treasure at `index` to next user (i + 1) and see if we did any better or not
*/
if (nextAnswer.min <= answer.min) {
answer = JSON.parse(JSON.stringify(nextAnswer));
minIndex = i;
}
/**
* Had we done any better,the changes might already be recorded in the answer.
* Because we are going to try and assign this treasure to the next user,
* Let us remove it from the current user before iterating further
*/
U[i] -= K[index];
bitset[i][index] = 0;
}
cache[answer.set[minIndex]] = answer;
return answer;
};
const ans = solve(0);
console.log("Difference: ", ans.min);
console.log("Treasure: [", K.join(", "), "]");
console.log();
ans.set.forEach((x, i) => console.log("User: ", i + 1, " [", x.join(", "), "]"));
// console.log("Cache:\n", cache);
通过不缓存整个位集,我们绝对可以改善使用的空间。从cahce中删除位集很简单。
答案 3 :(得分:0)
请考虑对于每个k
,我们可以将从A[i]
向左(sum A[i-j..i]
)增长的总和与f(k-1, i-j-1)
记录的所有可用间隔配对,并更新它们:对于每个间隔(low, high)
,如果总和大于high
,则new_interval = (low, sum)
;如果总和小于low
,则new_interval = (sum, high)
;否则,间隔保持不变。例如,
i: 0 1 2 3 4 5
A: [5 1 1 1 3 2]
k = 3
i = 3, j = 0
The ordered intervals available for f(3-1, 3-0-1) = f(2,2) are:
(2,5), (1,6) // These were the sums, (A[1..2], A[0]) and (A[2], A[0..1])
Sum = A[3..3-0] = 1
Update intervals: (2,5) -> (1,5)
(1,6) -> (1,6) no change
现在,我们可以通过识别和修剪上一轮k
期间的间隔来使此迭代效率更高 。
观看:
A: [5 1 1 1 3 2]
K = 1:
N = 0..5; Intervals: (5,5), (6,6), (7,7), (8,8), (11,11), (13,13)
K = 2:
N = 0: Intervals: N/A
N = 1: Intervals: (1,5)
N = 2: (1,6), (2,5)
Prune: remove (1,6) since any sum <= 1 would be better paired with (2,5)
and any sum >= 6 would be better paired with (2,5)
N = 3: (1,7), (2,6), (3,5)
Prune: remove (2,6) and (1,7)
N = 4: (3,8), (4,7), (5,6), (5,6)
Prune: remove (3,8) and (4,7)
N = 5: (2,11), (5,8), (6,7)
Prune: remove (2,11) and (5,8)
对于k = 2
,我们现在剩下以下修剪的记录:
{
k: 2,
n: {
1: (1,5),
2: (2,5),
3: (3,5),
4: (5,6),
5: (6,7)
}
}
我们已将k = 3
个可能的拆分列表中的n choose 2
迭代缩减为n
个相关拆分!
应用于k = 3
的通用算法:
for k' = 1 to k
for sum A[i-j..i], for i <- [k'-1..n], j <- [0..i-k'+1]:
for interval in record[k'-1][i-j-1]: // records are for [k'][n']
update interval
prune intervals in k'
k' = 3
i = 2
sum = 1, record[2][1] = (1,5) -> no change
i = 3
// sums are accumulating right to left starting from A[i]
sum = 1, record[2][2] = (2,5) -> (1,5)
sum = 2, record[2][1] = (1,5) -> no change
i = 4
sum = 3, record[2][3] = (3,5) -> no change
sum = 4, record[2][2] = (2,5) -> no change
sum = 5, record[2][1] = (1,5) -> no change
i = 5
sum = 2, record[2][4] = (5,6) -> (2,6)
sum = 5, record[2][3] = (3,5) -> no change
sum = 6, record[2][2] = (2,5) -> (2,6)
sum = 7, record[2][1] = (1,5) -> (1,7)
答案是5
与record[2][3] = (3,5)
配对,得出更新的间隔(3,5)
。我将修剪逻辑留给读者解决。如果我们想继续,这是k = 3
{
k: 3
n: {
2: (1,5),
3: (1,5),
4: (3,5),
5: (3,5)
}
}