我试图解决的问题是我们如何找到所有整数集[a1,a2,...,am]以便
a1 + a2 + ... + am = N
并使用约束ai >= 1
例如,如果M = 4,N = 7则有三个答案
[1,1,1,4]
[1,1,2,3]
[1,2,2,2]
答案 0 :(得分:1)
由于您必须打印总和为N的所有集合。您可以使用递归的完整搜索算法。在下面的代码中,M是集合中的数字数,N是所需的总和。
int M;
int N;
void run(){
M = 4;
N = 7;
int[] arr = new int[M];
print(arr, 0, N, 1);
}
// req holds the required sum for the numbers in the array from arr[from]
// to arr[M-1].
// "last" holds the last value that we had put in the array.
// The first call to the array will be with last=1.
void print(int[] arr, int from, int req, int last){
// Reached the end of the array and sum required 0.
if(from==M && req==0){
System.out.println(Arrays.toString(arr));
return;
}
// Either reached the end of the array but sum is not equal to N
// Or if we have not reached the end of the array but sum has already
// become more than or equal to N.
if(from==M || req<=0){
return;
}
for(int i=last; i<=req; i++){
arr[from] = i;
print(arr, from+1, req-i, i);
}
}
M = 4且N = 7的输出:
[1, 1, 1, 4]
[1, 1, 2, 3]
[1, 2, 2, 2]
M = 3且N = 10的输出:
[1, 1, 8]
[1, 2, 7]
[1, 3, 6]
[1, 4, 5]
[2, 2, 6]
[2, 3, 5]
[2, 4, 4]
[3, 3, 4]
答案 1 :(得分:1)
回答链接中的问题,刚接受。
这个想法很简单,假设我们知道每个部分的最大值是X
,并且我们想找到一种方法来划分这些文件柜以实现这一点,我们可以贪图地将它们划分为:
ith
机柜的总数大于X
。所以这是第一部分,类似地,我们可以选择其他部分。这种贪婪总能找到解决方案(如果存在)。最后,我们可以使用二分搜索来调整X的值,如果我们能找到一种分隔橱柜的方法,可以减少X,如果我们找不到,可以增加X.
以下是Java中的代码:
public class FairWorkload {
public int getMostWork(int[] folders, int workers) {
int[] data = new int[folders.length];
data[0] = folders[0];
for (int i = 1; i < data.length; i++) {
data[i] = data[i - 1] + folders[i];
}
if (workers == 1) {
return data[data.length - 1];
}
int start = 0;
int end = data[data.length - 1];
int result = Integer.MAX_VALUE;
while (start <= end) {
int mid = (start + end) / 2;
int index = 0;
for (int k = 0; k < workers && index < data.length; k++) {
int less = index > 0 ? data[index - 1] : 0;
int temp = index;
for (int i = index; i < data.length; i++) {
if (data[i] - less <= mid) {
temp = i;
} else {
break;
}
}
// System.out.println(data[temp] - less + " " + mid);
if(data[temp] - less > mid){
index = -1;
break;
}
index = temp + 1;
}
//System.out.println(mid + " " + index);
if (index != data.length) {
start = mid + 1;
} else {
result = Math.min(result, mid);
end = mid - 1;
}
}
return result;
}
public static void main(String[] args) {
int[] data = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1000};
System.out.println(new FairWorkload().getMostWork(data, 2));
}
}
答案 2 :(得分:0)
一种可能的解决方案是使用计数技术,找到满足[i] <= [length-1] - 2
的最右边的术语,然后尽可能地将所有其他术语展平到右边,保持[i] <= a [i + 1]。
import java.util.Arrays;
public class test {
public static void main(String[] args) {
test t = new test();
t.go();
}
private void go() {
int w = 3;
int sum = 10;
int[] terms = new int[w];
for (int i = 0; i < terms.length; i++) {
terms[i] = 1;
}
terms[w-1] = sum - w + 1;
System.out.println(Arrays.toString(terms));
for (int i = right_index(terms); i>=0; i = right_index(terms)) {
terms[i]++;
int a = terms[i];
int overflow = -1;
// balance all the terms to the right
for (int j = i+1; j < terms.length-1; j++) {
overflow += terms[j] - a;
terms[j] = a;
}
terms[terms.length-1] += overflow;
System.out.println(Arrays.toString(terms));
}
}
// find the rightmost index i, where [i] <= [ia.length-1] - 2
private int right_index(int[] ia) {
int max = ia[ia.length-1];
for (int i = ia.length - 1; i >= 0; i--) {
if (ia[i] <= max - 2)
return i;
}
return -1;
}
}