[使用动态编程的新解决方案]
我在这方面花了很多时间,希望它运作良好。我评论它是为了像往常一样清楚。希望这会有所帮助,我没有找到更有效的方法,抱歉。
package temp2;
public class Main {
private static int
X=1, //This i understood is the max number of subarray. Change it to find counterexample.
Y=2, //This is the number of elements you want as result. Change it to find counterexample.
VERY_LARGE_NUMBER=1000000;
private static int array[] = {1, 100, 2, 2, 100, 1}; //just your array. Change it to find counterexample. Remember to leave the bounds (9999) as i explained in the answer.
public static void main(String args[]){
System.out.println("Obtained result: "+alg(array.length-1, 0, 0, 0, false));
}
public static int alg(int index, int partialSum, int numberOfUsedArrays, int numberOfUsedElements, boolean beforeIsInResults){
/**
* If the remaning number to analize are equal than the max number of elements minus the number of elements found AND
* i can add them to the results adding a new subarray OR using the adjacent one, i add all the value to the result sum.
*/
if(index+1+numberOfUsedElements == Y && (numberOfUsedArrays<X || (beforeIsInResults && numberOfUsedArrays<=X))){
int summ = 0;
for(int i=0; i<=index; i++)
summ+=array[i];
return summ+partialSum;
}
/**
* If i don't have any subarray to create or to use (if is possible to connect to the adjacent) AND i don't enough elements
* in the computed solution i don't consider this solution.
*/
if((((numberOfUsedArrays > X && beforeIsInResults) || (numberOfUsedArrays >= X && !beforeIsInResults)) && numberOfUsedElements < Y )){ //Old condition i think is no more needed: || (index+1+numberOfUsedElements == Y && ((numberOfUsedArrays > X && beforeIsInResults) || (numberOfUsedArrays >= X && !beforeIsInResults)))){
return VERY_LARGE_NUMBER;
}
/**
* If the index is out of bound OR i don't have any more subarrays left OR i reach the max number of element of the result i return the computed solution.
*/
if( index < 0 || ((numberOfUsedArrays > X && beforeIsInResults) || (numberOfUsedArrays >= X && !beforeIsInResults)) || numberOfUsedElements >= Y )
return partialSum;
/**
* I check if the best solution contains OR not contain the selected index. The only difference from if to else is that in case in which i choose to
* add the element to the result is the element computed before (index+1) was selected no new array has been used else i need to update the number of array used.
*/
if(beforeIsInResults)
return Math.min(
alg(index-1, partialSum+array[index], numberOfUsedArrays, numberOfUsedElements+1, true),
alg(index-1, partialSum, numberOfUsedArrays, numberOfUsedElements, false));
else
return Math.min(
alg(index-1, partialSum+array[index], numberOfUsedArrays+1, numberOfUsedElements+1, true),
alg(index-1, partialSum, numberOfUsedArrays, numberOfUsedElements, false));
}
}
[旧的非工作解决方案]: 反例:{1, 100, 2, 2, 100, 1} x = 1, y = 2
我找到了这个算法。除非我弄错了,否则复杂度应该是 O(Y × 数组长度)。
n.b.所有这一切都假设您的 X 变量表示“子数组的最大数量”
Start: Find min in array not in result
add it to result
did we reach the max number of result?
(Yes: end and print results) (No: go to Continue)
Continue: Compute min subarrays in the results.
Is it equals to the max subarray (`Y`)?
(No: go to Start) (Yes:Continue2)
Continue2: Find minimum value near one subarray.
go to Continue.
我知道这有点令人困惑,但这还不是最糟糕的部分。
我制作了以下代码来测试我的算法。这可能是我写过的最糟糕的代码了。
我试图保持简单,避免任何“案例特殊控制”,例如在某些情况下,如果应该控制以避免任何索引超出范围异常(而不是这个,因为我很懒,我只是放置了一些大的无用的值)。
我已经尝试了你所有的组合并且它有效。我没有找到任何反例。
如果您需要更多说明,请询问(我明天会回复,因为在意大利这里是晚上;))
代码如下:
public class Main {
public static void main(String[] args){
int X=1000, //This i understood is the max number of subarray. Change it to find counterexample.
Y=3, //This is the number of elements you want as result. Change it to find counterexample.
temp, //This is just a value i used to store the minimum during the search along the array.
tempIndex, //This is the one that keeps the index of temp.
subarray=0, //This value will contain the minimum number of subarrays formed by the results. Since at the start there are no results, there are no subarray either. (to compare with X)
resultsSize=0; //This will used to store the number of results temporary found (to compare with Y)
int array[] = {9999,2,1,10,40,5,6,9999}; //just your array. Change it to find counterexample. Remember to leave the bounds (9999) as i explained in the answer.
/*If my professor saw me use two parallel arrays instead of an array of objects
*I think he might kill me, but as I said, I'm lazy and this code just serves to make an example
*/
boolean used[] = {false, false, false, false, false, false, false, false}; //Just used to chceck if one value is already used in results.
while(true){
try{
//The following code just find the minimum element not used.
temp=9998;
tempIndex=-1;
for(int i=0; i<array.length; i++){
if(array[i]<temp && !used[i]){
temp=array[i];
tempIndex=i;
}
}
//The following code add the found number to the results (just print it)
used[tempIndex] = true;
resultsSize++;
System.out.print(temp+" ");
//This is one of the two way to return with success. Basically we return when we found Y results.
if(resultsSize == Y ) {
System.out.println("\nDone.");
return;
}
/*When i add an element to the result 3 things may happen.
*The result isn't near to any result, so it would create a new subarray
*The result is near to just one result, no new subarray created
*The result is just in the middle of two other result, adding it will result in fusion on two subarrays into one.
*The following code just use this rule to compute the subarray number
*/
if(used[tempIndex-1] && used[tempIndex+1]){ //third case
subarray--;
}else if(!used[tempIndex-1] && !used[tempIndex+1]){ //first case
subarray++;
}
/*The following code will be executed only IF we reach the limit of subarrays. If so, he just try to add the smallest element without
*any subarray increment. If the subarrays get decremented (third case of the comment above) the while ends and the control returns back to the
*up side of this function early discussed.
*/
while(subarray == X){
//The following code just find the minimum element not used.
temp=9998;
tempIndex=-1;
for(int i=0; i<array.length; i++){
if(array[i]<temp && !used[i] && (used[i-1] || used[i+1])){
temp=array[i];
tempIndex=i;
}
}
//If this is true there are no minimum element near results which practically means that your 'Y' value is bigger than the length of the array
if(temp==9998){
System.out.println("\nYou shloud not ever come here.\ncheck if your 'Y' value is bigger than the length of the array");
return;
}
//The following code add the found number to the results (just print it)
used[tempIndex] = true;
resultsSize++;
System.out.print(temp+" ");
//This is one of the two way to return with success. Basically we return when we found Y results.
if(resultsSize == Y ){
System.out.println("\nDone.");
return;
}
//The following code checks with the new added result the number of subarrays get decremented.
//Remember that if subarrays get decremented the alg go back to the first part and search for minimum even non near to an existing subarray.
if(used[tempIndex-1] && used[tempIndex+1]){
subarray--;
}
}
} catch(Throwable e){ //Used for debugging, no more needed.
e.printStackTrace();
return;
}
}
}
}
让我知道这是否有用或只是浪费时间;)