题目描述
给定 (n) 个无标号的球,(n-1) 个的重量相同,剩下 (1) 个球的重量比这 (n-1) 个球略重
给定一个天平,每次可以用天平称量,天平的一边最多放 (m) 个球,求最劣情况下找出略重那个球的最小步数
题解
如果天平放的球的个数没有限制
最优决策是将球分成三堆
-
(3n),直接分成 (n, n, n) 就行了
-
(3n + 1),分成 (n, n, n+1),用天平称 (n,n) 这两堆,最劣的情况是那个特殊球在 (n+1) 里
-
(3n + 2),分成 (n, n+1, n+1),用天平称 (n+1,n+1) 这两堆,最劣的情况就是那个特殊球在这两个 (n+1) 里
如果天平有限制
最先会限制到上面的第三种情况,即 (n+1>m),总球数 (3n+2>3m-1),显然这时只能拿出两个 (m) 去称,最劣的情况是剩下没称的那一堆,即转移到 (f(n-2m)),这个显然可以 (Theta(1)) 转移
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
#define rint register int
#define rll register long long
using namespace std;
const int maxn = 1e5 + 50, INF = 0x3f3f3f3f;
inline ll read () {
rll x = 0, w = 1;
char ch = getchar ();
for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
return x * w;
}
ll n, m;
inline ll DFS (ll n) {
if (n == 1 || n == 0) return 0;
if (n >= 3 * m + 2) {
rll res = (n - m - 2) / (2 * m);
return DFS (n - 2 * res * m) + res;
} else {
if (n % 3 == 0) return DFS (n / 3) + 1;
else if (n % 3 == 1) return DFS (n / 3 + 1) + 1;
else return DFS (n / 3 + 1) + 1;
}
}
int main () {
n = read(), m = read();
printf ("%lld
", DFS (n));
return 0;
}