前面那道题太简单了,这里来一道稍微难点的。
有 N 个人,分成 M 组(2<=M<=N)打比赛,每组内部不竞争,每个人和不在同一组的其他人每人打一场。
比如有ABCD四个人,如果分2组,{ABC}{D}要打3场,{AB}{CD}打4场,
分3组{A}{B}{CD}打5场,分4组{A}{B}{C}{D}打6场。显见没有哪种分组能只打1场。
问题:有 N 个人,有没有哪种分组恰好打 K 场比赛?
bool fight(int N, int K);
2<=N<=100, 1 <= K <= 10000.
On Dec 28, 11:12 pm, sagasw <sag...@gmail.com> wrote:
> BTW,tag是面试,是你们公司用这个题目做面试么?
>
> ------------------------------------
> C++, Lua, living in Dalianhttp://sunxiunan.com/http://twitter.com/sagasw
> ------------------------------------
>
> 2009/12/28 Shuo Chen <giantc...@gmail.com>
bool fight(int N, int K);
这样不涉及文件读写等次要因素。再说我也没有那些测试集,评分标准自然也用不上了。
> C++, Lua, living in Dalianhttp://sunxiunan.com/http://twitter.com/sagasw
> ------------------------------------
>
> 2009/12/28 Shuo Chen <giantc...@gmail.com>
今天上班了,没那么多时间思考,只有趁着build时间写写纸面上的演算。
这个问题像是一个数学归纳问题(当然应该有更简洁的解法),我简单列了一下5个人的情况,
{1} {1} {1} {1} {1} 一人一组的话,那就是 4!
{2} {1} {1} {1} 这种情形是2!+ 2 * 3
{3} {1} {1} 这种 3 * 2 + 1!
{4} {1} 这种 4 * 1
{2} {2} {1} 这种2* 2 + 2 * 1 + 2 * 1
{2} {3} 这种是 2 * 3
归纳起来就是分组成员为1的个数为iOne + 1,
分组成员大于1(小于N)的个数为iNa, iNb, iNc
那么结果应该是iOne ! + iOne * iNa + iOne * iNb + iOne * iNc + iNb * iNc
当然这只是非常粗略的想,也许是错误的。
这时候问题就可以分成两部分,一部分是把人数分组,这个需要继续想想,
def partitions(n):
# base case of recursion: zero is the sum of the empty list
if n == 0:
yield []
return
# modify partitions of n-1 to form partitions of n
for p in partitions(n-1):
yield [1] + p
if p and (len(p) < 2 or p[1] > p[0]):
yield [p[0] + 1] + p[1:]
def gen_partitions_ms(n):
"""Generate all partitions of integer n (>= 0).
Each partition is represented as a multiset, i.e. a dictionary
mapping an integer to the number of copies of that integer in
the partition. For example, the partitions of 4 are {4: 1},
{3: 1, 1: 1}, {2: 2}, {2: 1, 1: 2}, and {1: 4}. In general,
sum(k * v for k, v in a_partition.iteritems()) == n, and
len(a_partition) is never larger than about sqrt(2*n).
Note that the _same_ dictionary object is returned each time.
This is for speed: generating each partition goes quickly,
taking constant time independent of n.
"""
if n < 0:
raise ValueError("n must be >= 0")
if n == 0:
yield {}
return
ms = {n: 1}
keys = [n] # ms.keys(), from largest to smallest
yield ms
while keys != [1]:
# Reuse any 1's.
if keys[-1] == 1:
del keys[-1]
reuse = ms.pop(1)
else:
reuse = 0
# Let i be the smallest key larger than 1. Reuse one
# instance of i.
i = keys[-1]
newcount = ms[i] = ms[i] - 1
reuse += i
if newcount == 0:
del keys[-1], ms[i]
# Break the remainder into pieces of size i-1.
i -= 1
q, r = divmod(reuse, i)
ms[i] = q
keys.append(i)
if r:
ms[r] = 1
keys.append(r)
yield ms
print can_m2k(500, 10000)
呢?
On Dec 29, 2:20 pm, 张沈鹏 <zsp...@gmail.com> wrote:
> 2009/12/29 Shuo Chen <giantc...@gmail.com>
你这个
print can_m2k(100, 4950)
要多长时间?
print can_m2k(500, 10000)
呢?
测试集是 fight(100, 1) 到 fight(100, 5000) 的结果,有5000行,怎么发?
要不我把我的代码发上来?
> 2009/12/29 Shuo Chen <giantc...@gmail.com>
一个指数时间的算法如何称得上"够用就好"?
can_m2k(100,4950) 在一台X5150上算了10分钟没有出结果。
can_m2k(40, 1), can_m2k(50, 1), can_m2k(60, 1), can_m2k(61, 1), can_m2k
(70,1) 的计算时间分别是:
0.8s,
5.0s,
28s,
34.4s,
140s
大致可以看出,人数每增加10,时间是5倍。
On Dec 29, 3:01 pm, 张沈鹏 <zsp...@gmail.com> wrote:
> 2009/12/29 Shuo Chen <giantc...@gmail.com>
>
#!/usr/bin/python
def memo(func):
cache = {}
def f(*args):
if args in cache:
return cache[args]
r = func(*args)
cache[args] = r
return r
return f
@memo
def ok(n, k):
if k == 0 and n > 0: return True
if k < 0 or n < 0 or 2*k > n**2: return False
for x in xrange(1, n+1): # last
if ok(n-x, k-x*(n-x)): return True
return False
while True:
try:
n, k = map(int, raw_input().strip().split())
except EOFError:
break
print ok(n, k)
--
Alecs King
这个问题无法直接下手,但是可以考虑下面这些情况:
1. 如果把其中某 1 个人分为一组,他和剩下的 99 个人肯定要打 99 场比赛,不管这 99 个人如何分组。
那么问题规模缩小,转化为 99 个人能不能打 1000-99=901 场比赛。如果能打,100个人就能打1000场。
2. 如果把其中某 2 个人分为一组,他和剩下的 98 个人肯定要打 98*2 场比赛,不管这 98 个人如何分组。
那么问题规模缩小,转化为 98 个人能不能打 1000-98*2 = 804 场比赛。如果能打,100个人就能打1000场。
2. 如果把其中某 3 个人分为一组,他和剩下的 97 个人肯定要打 97*3 场比赛,不管这 97 个人如何分组。
那么问题规模缩小,转化为 97 个人能不能打 1000-97*3 = 709 场比赛。如果能打,100个人就能打1000场。
......
99. 如果把其中某 99 个人分为一组,他和剩下的 1 个人肯定要打 99 场比赛,不管这 1 个人如何分组。
那么问题规模缩小,转化为 1 个人能不能打 1000-99 = 901 场比赛。如果能打,100个人就能打1000场。
于是很容易写出递归算法,再加上把算过的结果缓存起来,结果就出来了。
#include <stdio.h>
#include <stdlib.h>
const int MAX_N = 500;
bool impossible[MAX_N+1][MAX_N*MAX_N/2];
bool baidu(int people, int fights)
{
if (fights == 0)
return true;
if (fights < 0 || (people*(people-1)/2) < fights)
return false;
if (impossible[people][fights])
return false;
for (int p = 1; p < people; ++p) {
if(baidu(people - p, fights - p*(people-p)))
return true;
}
impossible[people][fights] = true;
return false;
}
int main(int argc, char* argv[])
{
int n = atoi(argv[1]);
int k = atoi(argv[2]);
printf("%s\n", baidu(n, k) ? "YES" : "NO");
参考答案:
1. 100 次
2. x = 1795 等数。
思考题:对于 1<=x<=4950,baidu(100,x) 的平均调用次数是多少,中位数是多少?
On Dec 30, 1:43 pm, Hongzhang Liu <hongzhang....@gmail.com> wrote:
> 嗯,我跑了一下,Shuo Chen的算法非常简单,但效率可能并不好。fight(100, 1)这种情况计算的复杂度就很高。
>
> 2009/12/30 Jacky, Z <fanste...@gmail.com>
>
> test.zip
> 3KViewDownload
我发个递推版的,直接把表推出来:
bool possible[MAX_N+1][MAX_N*MAX_N/2];
void build(int people)
{
possible[people][0] = true;
for (int p = 1; p < people; ++p) {
int rem = people - p;
int add = p*rem;
int up = rem*(rem-1)/2;
for (int i = 0; i <= up; ++i) {
if (possible[rem][i]) // ***
possible[people][i+add] = true;
}
}
}
int main(int argc, char* argv[])
{
int n = atoi(argv[1]);
possible[1][0] = true;
for (int people = 2; people <= n; ++people)
build(people);
// print(n);
}
竞猜:代码中标有***那句的执行次数的big-O表示。候选答案:
1. O(n)
2. O(n**2)
3. O(n**3)
4. O(n**4)
5. O(n**5)
6. O(n * log n)
7. O(n * n * log n)
以上的 n 均为 main 中的 n。
On Dec 30, 6:13 pm, "Jacky, Z" <fanste...@gmail.com> wrote:
> *Shuo Chen *不妨测试一下剪枝后性能怎么样。
>
> 2009/12/30 Shuo Chen <giantc...@gmail.com>
PRINT_N_CACHE = {}
def print_n(n):
if n<=1:
return (0,)
if n in PRINT_N_CACHE:
return PRINT_N_CACHE[n]
result = set((0,n-1))
for i in range(1,n):
offset = i*(n-i)
for j in print_n(i):
result.add(j+offset)
r = tuple(result)
PRINT_N_CACHE[n] = r
return r
print sorted(print_n(100))
Zues:work ~/test:cat setup.py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext
ext_modules = [Extension("mkn", ["mkn.pyx"])]
setup(
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)
Zues:work ~/test:cat test.py
from mkn import print_n
for i in range(501):
print "%s,"%(",".join(map(str,sorted(set(print_n(i))))))
Zues:work ~/test:cat mkn.pyx
PRINT_N_CACHE = {}
def print_n(n):
if n<=1:
return (0,)
if n in PRINT_N_CACHE:
return PRINT_N_CACHE[n]
result = set((0,n-1))
for i in range(1,n):
offset = i*(n-i)
for j in print_n(i):
result.add(j+offset)
r = tuple(result)
PRINT_N_CACHE[n] = r
return r
Zues:work ~/test:python setup.py build_ext --inplace
running build_ext
On Dec 30 2009, 1:43 pm, Hongzhang Liu <hongzhang....@gmail.com> wrote: