checkio——batteriesloading

  CheckiO上面的一道题目 Batteries Loading

  这倒题目的意思就是,给出一堆电池,每个电池有不同的重量,电池装在两只手上,怎样装载,才能使两只手上的电池重量之差最小,给出了一些例程:

checkio([10,10]) == 0
checkio([10]) == 10
checkio([5, 8, 13, 27, 14]) == 3
checkio([5,5,6,5]) == 1
checkio([12, 30, 30, 32, 42, 49]) == 9
checkio([1, 1, 1, 3]) == 0

  这道题很明显是动态规划问题,但我对动态规划并不是很熟悉,于是看了一阵时间的背包问题。

  事实上,这道题可以转化为背包问题,即,要使两只手臂装载的电池重量差最小,那应该让每只手臂越接近总重量的一半,才能使其差最小。

  在此,背包的容量就是总重量sum的一半,即halfsum,将所给的电池装入一个背包容量为halfsum的背包中,怎样装,能使箱子的重量达到最大?

  所以,首要问题,即找到最优子结构

  问题是当前阶段的剩余空间最小,并不意味下一阶段的剩余空间也一定最小,即该问题并不具备最优子结构的特征。但如果将装背包的体积作为状态的话,则阶段间的状态转移关系顺其自然,可使得最优化问题变为判定性问题。设状态转移方程

    f[i,j]——在前i个物品中选择若干个物品(必须包括物品i)装箱,其体积正好为j的标志。显然f[i,j]=f[i-1,j-box[i]],即物品i装入箱子后的体积正好为j的前提是f[i-1,j-box[i]]=true。初始时,f[0,0]=true(1≤i≤n,box[i]≤j≤halfsum)。

  我首先用C++代码实现,因为现在对C++较为熟悉:

 1 #include <iostream>
 2 #include <stdlib.h>
 3 #include <cstring>
 4 
 5 #define maxlength 100
 6 
 7 using namespace std;
 8 
 9 int things[maxlength];
10 
11 int main()
12 {
13     cout << "Hello World!" << endl;
14     int in = 0;
15     int n;
16 
17     while(cin >> n && cin.good())
18     {
19         things[in] = n;
20         in++;
21     }
22 
23     int sum = 0;
24 
25     if(in == 1)
26     {
27         cout << "Min minus is " << things[0] << endl;
28 
29         return 0;
30     }
31 
32     for(int i = 0; i < in; i++)
33     {
34         sum += things[i];
35     }
36 
37     /* 取总数值的一半作为背包的容量
38      */
39     int halfsum = sum/2;
40 
41     int* f0 = (int* )malloc((halfsum + 1) * sizeof(int));
42     int* f1 = (int* )malloc((halfsum + 1) * sizeof(int));
43 
44     memset(f0, 0, (halfsum + 1)*sizeof(int));
45     memset(f1, 0, (halfsum + 1)*sizeof(int));
46 
47     f0[0] = 1;
48 
49     /*
50      *装入背包, f0记录i-1时刻背包的状态
51      *f1记录i时刻背包的状态
52      *f0[j]表示当前容量为j的背包恰好装满时,其值为1,否则为0, 同理f1[j]
53      *初始状态,只有f0[0]为1
54      *对于第i个物品,当f0[j-things[i]] = 1时,说明装入i物品,能使背包恰好装满,即f1[j] = 1, 即当前状态更新
55      */
56     for(int i = 0;i < in;i++)
57     {
58         for(int j = things[i];j <= halfsum; j++)
59         {
60             if(f0[j-things[i]])
61             {
62                 f1[j] = 1;
63             }
64         }
65         for(int k = 1;k <= halfsum; k++)
66         {
67             f0[k]=f1[k];
68         }
69     }
70 
71     int k = halfsum;
72     while(!f0[k])
73     {
74         k--;
75     }
76 
77     /*
78      *因为有两只背包,当其中一直装了k个时, 另一个有sum-k个
79      *则差为 sum-k-k
80      */
81     int minminus = sum - 2*k;
82 
83     cout << "Min minus is " << minminus << endl;
84 
85     return 0;
86 }

  其次转化为python的代码,这里碰到一个小问题,对于python而言, 如果令halfsum = sum/2的话,python会自动将halfsum默认设置为float型,所以需要前面加个int转换一下:

 1 def checkio(stones):
 2     '''
 3     minimal possible weight difference between stone piles
 4     '''
 5     slen = len(stones)
 6      
 7     if slen == 1 :
 8         return stones[0]
 9      
10     sum = 0
11     for i in stones :
12         sum = sum + i
13      
14     halfsum = int(sum/2)
15      
16     f0 = [0] * (halfsum + 1)
17     f1 = [0] * (halfsum + 1)
18      
19     f0[0] = 1
20      
21     for i in stones :
22         for j in range(i, halfsum+1) :
23             if f0[j-i] :
24                 f1[j] = 1
25         for k in range(1,  halfsum+1) :
26             f0[k] = f1[k]
27      
28     k = halfsum
29     while f0[k] == 0:
30         k = k-1
31      
32     minminus = sum - 2*k
33      
34     return minminus
35      
36  
37 if __name__ == '__main__':
38     assert checkio([10,10]) == 0, 'First, with equal weights'
39     assert checkio([10]) == 10, 'Second, with a single stone'
40     assert checkio([5, 8, 13, 27, 14]) == 3, 'Third'
41     assert checkio([5,5,6,5]) == 1, 'Fourth'
42     assert checkio([12, 30, 30, 32, 42, 49]) == 9, 'Fifth'
43     assert checkio([1, 1, 1, 3]) == 0, "Six, don't forget - you can hold different quantity of parts"
44     print ('All is ok')

  当然,此题也有暴力解法,即用python的函数,求得输入序列的全排列,然后枚举每一个组合的差值,最后从其中选出最小值。

  

原文地址:https://www.cnblogs.com/moondark/p/2951908.html