Topcoder SRM 358:BalanceScale
现在有n件物品集合V,每件有一个重量Wi,现在要从里面选出一个集合S,使得V-S中的物品都能由S中的物品称出来,即在一个天平的的左边放入V-S中的1件物品,那么必定可以从S中选出一些物品(可以无限使用)放在右边,使得天平平衡。
现在要求集合S中元素个数的最小值。
现在,我们先求出Wi(i=1,2,3...n)的最大公倍数g,然后把每个Wi都除以g,这样gcd(Wi)=1,这样并不会影响最后的结果。现在证明如果V中的一个子集S的最大公倍数为1,那么V中的元素都可以有S中的元素称出来。
证明用的是 Bézout's identity定理。
那么现在的问题转换成从集合V中选出最小的集合S,使得集合S的公倍数于集合V的公倍数相同(同为1)。
设DP[x]为以x为最大公倍数的最小集合的个数,通过DP求解(其实就是BFS搜索),那么最后的结果就是DP[1]
下面是DFS的代码:
现在要求集合S中元素个数的最小值。
现在,我们先求出Wi(i=1,2,3...n)的最大公倍数g,然后把每个Wi都除以g,这样gcd(Wi)=1,这样并不会影响最后的结果。现在证明如果V中的一个子集S的最大公倍数为1,那么V中的元素都可以有S中的元素称出来。
证明用的是 Bézout's identity定理。
那么现在的问题转换成从集合V中选出最小的集合S,使得集合S的公倍数于集合V的公倍数相同(同为1)。
设DP[x]为以x为最大公倍数的最小集合的个数,通过DP求解(其实就是BFS搜索),那么最后的结果就是DP[1]
int d[10000100];
class BalanceScale
{
public:
int takeWeights(vector <int> w)
{
int n = w.size();
int g = w[0]; for( int i = 1; i < n; i++ ) g = gcd( g, w[i] );
for( int i = 0; i < n; i++ ) w[i] /= g;
sort( w.begin(), w.end() );
if( w[0] == 1 ) return 1;
queue< int > q;
memset( d, 1, sizeof( d ) );
for( int i = 0; i < n; i++ ) { q.push( w[i] ); d[w[i]] = 1; }
while( !q.empty() && d[1] == 0x01010101 )
{
int u = q.front(); q.pop();
for( int i = 0; i < n; i++ )
{
int v = gcd( u, w[i] );
if( d[v] == 0x01010101 ) { d[v] = d[u] + 1; q.push( v ); }
}
}
return d[1];
}
};
class BalanceScale
{
public:
int takeWeights(vector <int> w)
{
int n = w.size();
int g = w[0]; for( int i = 1; i < n; i++ ) g = gcd( g, w[i] );
for( int i = 0; i < n; i++ ) w[i] /= g;
sort( w.begin(), w.end() );
if( w[0] == 1 ) return 1;
queue< int > q;
memset( d, 1, sizeof( d ) );
for( int i = 0; i < n; i++ ) { q.push( w[i] ); d[w[i]] = 1; }
while( !q.empty() && d[1] == 0x01010101 )
{
int u = q.front(); q.pop();
for( int i = 0; i < n; i++ )
{
int v = gcd( u, w[i] );
if( d[v] == 0x01010101 ) { d[v] = d[u] + 1; q.push( v ); }
}
}
return d[1];
}
};
下面是DFS的代码:
import java.util.*;
public class BalanceScale {
int gcd(int x, int y) {
while (y != 0) {
int t = x % y; x = y; y = t;
}
return x;
}
int[] w;
int answer;
void bt(int i, int d, int c) {
if (c >= answer) {
return;
}
if (i == w.length) {
if (d == 1) {
answer = c;
}
return;
}
int d1 = gcd(d, w[i]);
if (d1 != d) {
bt(i + 1, d1, c + 1);
}
bt(i + 1, d, c);
}
public int takeWeights(int[] weight) {
int d = 0;
for (int x : weight) {
d = gcd(d, x);
}
for (int i = 0; i < weight.length; i++) {
weight[i] /= d;
}
w = weight;
answer = weight.length;
bt(0, 0, 0);
return answer;
}
}
public class BalanceScale {
int gcd(int x, int y) {
while (y != 0) {
int t = x % y; x = y; y = t;
}
return x;
}
int[] w;
int answer;
void bt(int i, int d, int c) {
if (c >= answer) {
return;
}
if (i == w.length) {
if (d == 1) {
answer = c;
}
return;
}
int d1 = gcd(d, w[i]);
if (d1 != d) {
bt(i + 1, d1, c + 1);
}
bt(i + 1, d, c);
}
public int takeWeights(int[] weight) {
int d = 0;
for (int x : weight) {
d = gcd(d, x);
}
for (int i = 0; i < weight.length; i++) {
weight[i] /= d;
}
w = weight;
answer = weight.length;
bt(0, 0, 0);
return answer;
}
}