C 将时间分为两个方框,并找出最小差异

C 将时间分为两个方框,并找出最小差异,c,algorithm,recursion,C,Algorithm,Recursion,开始学习递归,我被这个简单的问题困住了。我相信有更多的优化方法可以做到这一点,但首先我尝试学习bruteforce方法 我有A包和B包,有n个项目每个项目都有一定的时间(小数点后两位的浮动)。这样做的目的是通过两个袋子分配物品,并获得两个袋子之间的最小差异。想法是尝试所有可能的结果 我认为只有一个包(比如说A包)中有,因为另一个包将包含A包中没有的所有项目,因此差值将是总时间总和的绝对值-2*A包中项目时间的总和 我这样调用递归函数: min = total_time; recursive(0,

开始学习递归,我被这个简单的问题困住了。我相信有更多的优化方法可以做到这一点,但首先我尝试学习bruteforce方法

我有A包和B包,有
n个项目
每个项目都有一定的时间(小数点后两位的浮动)。这样做的目的是通过两个袋子分配物品,并获得两个袋子之间的最小差异。想法是尝试所有可能的结果

我认为只有一个包(比如说A包)中有,因为另一个包将包含A包中没有的所有项目,因此差值将是总时间总和的绝对值-2*A包中项目时间的总和

我这样调用递归函数:

min = total_time;
recursive(0, items_number - 1, 0);
该函数的代码如下所示:

void recursive(int index, int step, float sum) {
    sum += items_time[index];
    float difference = fabs(total_time - 2 * sum);

    if (min > difference) {
        min = difference;
    }

    if (!(min == 0.00 || step == 1 || sum > middle_time)) {
        int i;
        for (i = 0; i < items_number; i++) {
            if (i != index) {
                recursive(i, step - 1, sum);
            }
        }
    }
}
void recursive(整数索引、整数步长、浮点和){
总和+=项目时间[索引];
浮动差=fabs(总时间-2*和);
如果(最小值>差值){
最小值=差值;
}
如果(!(最小==0.00 | |步==1 | |和>中间时间)){
int i;
对于(i=0;i
假设我有4个项目的时间
1.23、2.17、2.95、2.31

我得到的结果是
0.30
。我相信这是正确的结果,但我几乎可以肯定,如果这是纯粹的改变,因为如果我尝试更大的情况,程序会在一段时间后停止。可能是因为递归树变得更大了


有人能给我指个方向吗?

你的问题叫做“问题”。这是NP难的,在某一点之后,它将需要一段很长的时间才能完成:随着要测试的案例数量的增长,树将以指数形式增大


分区问题是众所周知的,并且在internet上有很好的文档记录。存在一些优化的解决方案

您的方法不是简单的暴力方法,它只是遍历项目列表并递归地将其放入包A和包B中,选择差异最小的情况,例如:

double recurse(double arr[], int n, double l, double r)
{
    double ll, rr;

    if (n == 0) return fabs(l - r);

    ll = recurse(arr + 1, n - 1, l + *arr, r);
    rr = recurse(arr + 1, n - 1, l, r + *arr);

    if (ll > rr) return rr;
    return ll;
}
(这段代码非常幼稚——它并不是很早就出现明显的非最佳情况,而且在交换行李A和行李B的情况下,每种情况下计算两次也会浪费时间。然而,这是一种蛮力。)

最大递归深度是项数
n
,调用递归函数
2^n-1

在您的代码中,您可以将同一物品反复放入袋子中:

    for (i = 0; i < number_of_pizzas; i++) {
        if (i != index) {
            recursive(i, step - 1, sum);
        }
    }
for(i=0;i
此循环阻止您处理当前项目,但将愉快地处理在早期递归中第二次(或第三次)放入包中的项目。如果你想使用这种方法,你必须保持哪个物品在哪个袋子里的状态


另外,我不明白你的
步骤。从
步骤-1开始,当
步骤==1
时停止递归。这意味着您正在考虑
n-2
项。我知道其他物品在另一个袋子里,但这是一个奇怪的情况,它不会让你找到解决方案,比如说,
{8.0,2.4,2.4,2.8}

好的,在澄清之后,让我(希望)为你指出一个方向:

让我们假设您知道
n
是什么,在
n项中提到。在您的示例中,它是
2n
4
,使
n=2
。让我们选择另一个
n
,这次是
3
,我们的
时间应该是:

1.00
2.00
3.00
4.00
5.00
6.00
现在,我们已经知道答案是什么了;您所说的都是正确的,最佳情况下,每个行李的
n=3
时间
s总计为
中间时间
,在这种情况下为
21/2=10.5
。由于整数可能永远不会和带有小数点的数字相加,
10.5:10.5
在本例中可能永远无法实现,但是
10:11
可以,并且您可以通过
6.00+3.00+1.00
(3个元素)获得
10
,因此。。。是的,答案就是
1

你会让电脑怎么计算呢?好;回想一下我一开始说的话:

让我们假设您知道什么是n

在这种情况下,一个天真的程序员可能会简单地将所有这些放在2或3个嵌套的
for
循环中
2
如果他/她知道另一半将在您选择一半时确定(只需固定我们组中的第一个元素,因为该元素将包含在其中一个组中),您也知道<代码>3
如果他/她不知道的话。让我们用
2

...
float difference;
int i;
for ( i = 1; i < items_number; i++ ) {
    sum = items_time[0] + items_time[i];
    int j;
    for ( j = i + 1; j < items_number; j++ ) {
        sum += items_time[j];
        difference = fabs( total_time - 2 * sum );
        if ( min > difference ) {
            min = difference;
        }
    }
}
...
。。。
浮差;
int i;
对于(i=1;i差值){
最小值=差值;
}
}
}
...
让我对代码稍加评论,以便更快地理解:在第一个循环中,它会将第0次、第1次和第2次相加,如您所见;然后它将执行与您相同的检查(计算
差异
,并将其与
min
进行比较)。让我们称之为
012
组。要检查的下一组将是
013
,然后是
014
,然后是
015
;然后
023
,依此类推。。。将检查将6分为两个3的每个可能组合

这个操作对计算机来说应该不会有什么累人的问题。即使使用这种简单的方法,最大的尝试次数也将是3次与6次唯一el组合的次数