UVA 562 Dividing coins

我自己用的方法是把所有可能的組合列出來, 再找最接近的那一個.
想起來比較簡單, 不過慢一點.

正確的方法是dp, dp[n] 中放的是最接近 n 的組合的數值.
除了 dp 之外, 他有一個假設, 如果 r 是最接近 n/2 的值, 那會有 n-r 的組合, 而 r 和 n-r 兩者之間一定有一個比 n/2 少. 所以只要由 n/2 向下找. 另外次序一定要由大到小, 不然會出現錯誤, 除非用兩維列陣.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <cstdio>
#include <cmath>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

bool visited[50010];
vector<int> coins;
vector<int> allpossible;
vector<int> tmp;

int n, m, v, sumofall;
int newv, curv;
double halfv;

bool isnear(const int a, const int b) {
return abs(sumofall - 2*a) < abs(sumofall - 2*b);
}

int main() {
scanf("%d", &n);
for(int i = 0; i < n; ++i) {
coins.clear();
allpossible.clear();
sumofall = 0;
memset(visited, false, sizeof(visited));

scanf("%d", &m);
for(int j = 0; j < m; ++j) {
scanf("%d", &v);
coins.push_back(v);
sumofall += v;
}

halfv = sumofall/2.0;
visited[sumofall] = true;
allpossible.push_back(sumofall);
for(int j = 0; j < m; ++j) {
tmp.clear();
curv = coins[j];
for(int k = 0; k < allpossible.size(); ++k) {
newv = allpossible[k] - curv;
if(!visited[newv]) {
visited[newv] = true;
tmp.push_back(newv);
}
}
for(int l = 0; l < tmp.size(); ++l) {
allpossible.push_back(tmp[l]);
}
}

sort(allpossible.begin(), allpossible.end(), isnear);
printf("%d\n", abs(sumofall - 2*allpossible[0]));
}
return 0;
}

dp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;

int main(){
int n;
while( scanf("%d", &n) != EOF ){
for( int testcase = 0 ; testcase < n ; ++testcase ){
int m;
scanf("%d", &m);

int sum = 0;
int coins[105] = {0};
for( int i = 1 ; i <= m ; ++i ){
scanf("%d", &coins[i]);
sum += coins[i];
}

int average = sum / 2;
vector<int> dp( average+5, 0 );
for( int i = 1 ; i <= m ; ++i ){
for( int j = average ; j >= coins[i] ; --j ){
dp[j] = max( dp[j], dp[j-coins[i]] + coins[i] );
}
}

printf("%d\n", (sum-dp[average]) - dp[average]);
}
}
return 0;
}