IBM Ponder this 2016 August

r_64 posted @ 2016年9月04日 15:22 in 未分类 with tags ibm , 866 阅读

IBM最近的题水得不正常→_→

这个月的题目翻译就是,有$10$个袋子,里面各有$N$个硬币。有的袋子里只有10g的真币,有的袋子里只有9g的假币。允许你只用一个准确的秤称量一次,要求确定哪些袋子里的是假币。$N\ge 1024$。

这太水辣!第$i$个袋子取出$2^{i-1}$个,称总重量,二进制分解就好。

现在顶多三个袋子的假币,且$N=174$,求一种称量方法。解决$N$更小的问题就有bonus。

注:这篇博客里没有答案。。想要答案的自己跑程序去。

目前做到了$N=157$。。。用了一个小程序。

令$f_i$表示从第$i$个袋子里拿出多少,那么要求就是所有$f_i$,所有$f_i+f_j(i\ne j)$,所有$f_i+f_j+f_k(i,j,k\text{两两不同})$都不相同。

怎么判断一个$f$是否合法呢?令$G_a$表示$a$能否表示成$f_i$或$f_i+f_j$或$f_i+f_j+f_k$。考虑把数一个一个加入,加入的时候用$G$判断与之前的是否产生冲突, 加入之后更新$G$。具体见代码的okay()add()函数。

现在要产生$f$了。。就乱搞。。每次随机加入一个$[1,N]$内的数到$f$中,如果$[1,N]$中没有加入后仍合法的数就随机删一个$f$中已经有的数。

这个方法效果不错。。不过还是要看脸(随机数种子),随机数种子好的话一下就出解,不好的话要等很久(反正我几秒没跑出来就掐了。。也许永远也跑不出来呢)。

跑出来了就可以手动调$N$的值了。

#include <bits/stdc++.h>
using namespace std;
int f[233], G[23333];
int n;
int okay(int v){
  if (G[v]) return 0;
  for (int j = 1; j <= n; j++) if (G[f[j] + v]) return 0;
  for (int j = 1; j <= n; j++)
    for (int k = j + 1; k <= n; k++)
      if (G[f[j] + f[k] + v]) return 0;
  return 1;
}
void add(int v, int d){
  //d == 1 -> add, d == 0 -> del
  G[v] = d;
  for (int j = 1; j <= n; j++) G[f[j] + v] = d;
  for (int j = 1; j <= n; j++)
    for (int k = j + 1; k <= n; k++)
      G[f[j] + f[k] + v] = d;
}

void add(int x){add(x, 1); f[++n] = x;}
void del(int x){swap(f[x], f[n]); n--; add(f[n + 1], 0);}

int V = 174;
int dead(){
  for (int i = 1; i <= V; i++) if (okay(i)) return 0;
  return 1;
}

int main(){
  srand(time(0));
  while (1){
    if (n == 10){
      for (int i = 1; i <= n; i++) printf("%d ", f[i]);
      return 0;
    }
    if (dead()) del(rand() % n + 1);
    else{
      int x;
      do {x = rand() % V + 1;} while (!okay(x));
      add(x);
    }
  }
  return 0;
}

upd 8.4

我好像得到了两颗星。。ibm说两颗星的条件是求出最小的$N$。。(然而我并没有证明这个$N$是最小的啊,我都没有意料到呢

但是这个一定是可以证明的。。不然ibm也不敢咬定$157$是最小的。。这个就当一个坑了

upd 9.4

ibm的题解也没证明157是最小的。。而且它的解跟我给的完全一样。。


登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter