N, stairs

问题求解与程序设计
第三讲
称重问题
李文新
2004.2 – 2004.6
内容提要





作业总结 - 1008
作业总结 - 1013
何林冬令营报告 – 称球问题
自学及讨论 – 征服者
作业
作业总结 - 1008
 题意
• Haab 19个月 前18个月每月20天 第19个月5天
0-19 月名 0-5 月名
• Tzolkin 13个月 天数为20个轮转
1mix 2--- 3--- …
 问题
• 将Haab日期转换成Tzolkin日期
 源程序
1008 源程序
作业总结 - 1013
 题意
• 12枚硬币,其中一枚是假币,可能轻也可能重
• 称三次,每次左右硬币数目相等,结果:轻重平
 问题
• 求出假币,并给出其轻重
 源程序
• 1013源程序
长沙雅礼中学 何林
一类称球问题的
解法
问题的提出
 给定N个球
 有个比标准球重的次品混入其中
 你有一架天平,用最少的次数找出这个次品。
N
1 = 3
2
3
2
1
①是次品
1
2
1
2
②是次品
③是次品
N=3时称1次就可
以找出次品
1
2
4
NA = 9
3
5
6
B
A
次品在A中
A
B
次品在B中
A
B
次品在C中
7
B
8
9
C
• 通过一次称量,
可以把次品可能存
在的范围从9个,
缩小到3个
• N = 3的时候一次
就能称出次品
N = 9时称2次
更一般的情况
N = 3k
1
2
……
k
A
1
2
……
k
B
1
2
……
k
C
更一般的情况
B
A
次品在A中
A
B
A
B
次品在B中
次品在C中
范围缩小
到原来的
1/3
更一般的情况
 n = 3k+1, n = 3k+2和n=3k类似,也是均分
成三堆
 每次称量把范围大致缩小到原来的1/3
 因此:从n个球中找次品至多要称[log3n]次。
([]统一表示取上整)
判定树
[log3n]无疑是可行解。
最优性
为什么三分?
因为天平只有三种可能:
左偏、右偏、平衡
判定树
称(1, 2)
>
1
=
3
<
2
 叶子代表结果
 非叶子代表一次称量
 每个非叶子节点都有三个孩子,表示天
平左偏、右偏、平衡
判定树
比较(1,2,3)与(4,5,6)
>
比较(1)与(2)
>
1
=
3
<
=
比较(7)与(8)
比较(4)与(5)
>
>
<
2
7
=
9
<
8
4
判定树的深度就是称量次数
一个有意义的判定树至少n个叶子节点
=
6
<
5
判定树
 N个叶子的三叉树的深度h >= [log3n]
[log3n]是最优解
小结
 引进了有力工具:判定树。将主观的直觉严
谨化。
 三分法是解决这类问题的根本着眼点。
 三分时必须充分的均匀
Problem
Conqueror’s batalion
Table of Contents
The problem
Solution
The problem
 CENTRAL EUROPEAN OLYMPIAD IN INFORMATICS





30 June – 6 July 2002
Day 1: conquer
Conqueror’s battalion
Time limit: 1 s
Memory limit: 16 MB
The problem
In the whole history of mankind
one can find several curious
battles, like the following one in
France, in 1747. . .
The problem
There was a fortress in Bassignac-leHaut, a small village lying on the left bank
of river Dordogne, just over the Chastang
dam. From the dam up to the fortress
there was a wide staircase made out of
red marble.
The problem
One day in the morning, the guard
spotted a large battalion
Approaching the fortress, with a
dreaded leader – The Conqueror.
The problem
When The Conqueror reached the
fortress, he was already awaited by its
commandant. The commandant
proposed: “I see that you have many
soldiers behind you, standing on the
stairs. We can play a small ‘game’:
The problem
In each round, you will divide your
soldiers into two groups in an arbitrary
way. Then I will decide which one of
them stays and which one goes home.
Each soldier that stays will then move
up one stair.
The problem
If at least one of your soldiers reaches
the uppermost stair, you will be the
winner, in the other case, you will be the
loser.
The problem
The Conqueror immediately liked
this game, so he agreed and started
to ‘conquer’.
The problem
 Task
Your role is The Conqueror’s now. There
are N stairs to the fortress (2 <= N <=
2000) and you have at most 1 000 000 000
soldiers.
The problem
For each stair, you are given the number
of soldiers standing on it, with number 1
being the uppermost stair and N the
bottom one. None of your soldiers
stands on stair 1 at the beginning.
The problem
For each starting position given to your
program, if the position is winning (i.e. there
is a strategy that enables you to win the
game regardless of your opponent’s moves),
Your program should win. Otherwise it
should just play the game (and lose)
correctly.
The problem
This is an interactive problem; you will play
against a library as specified below. In
each round, your program will describe a
group of soldiers to our library. The library
returns 1 or 2 specifying which group of
soldiers should stay (1 means the group you
described, 2 means the rest of the soldiers).
The problem
In case the game ends (either because
you won or there are no more soldiers
in the game), the library will terminate
your program correctly. Your program
may not terminate in any other way.
The problem
Library interface
The library libconq provides two routines:
• start – returns the number N and fills an
array stairs with numbers of soldiers
standing on the stairs (i.e. there are stairs[i]
soldiers standing on stair i)
The problem
• step – takes an array subset (with at
least N1 elements), describing the
group of soldiers you chose, and
returns 1 or 2 as described above; the
group of soldiers is specified by
numbers of soldiers on each stair, as in
the start function
The problem
If you fail to specify a valid group of
soldiers, the game will be terminated
and your program will score zero points
for the particular test case. Please note
that also in C/C++ the stairs are
numbered starting from 1.
The problem
Following are the declarations of these
routines in FreePascal and C/C++:
 procedure start(var N: longint; var
stairs:array of longint);
 function step(subset:array of longint):
longint;
 void start(int *N, int *stairs);
 int step(int *subset);
The problem
Below you can find examples of library
usage in both FreePascal and C/C++; both
fragments do the same – start the game and
then play one round, with the chosen group
containing all soldiers on randomly chosen
stairs. Your real program will probably play
the rounds in an infinite loop.
The problem
You are strongly encouraged to define
the arrays stairs and subset in the same
way as they are defined in the example
below.
The problem
FreePascal example:
uses libconq;
var stairs: array[1..2000]
of longint;
subset: array[1..2000]
of longint;
i,N,result: longint;
...
start(N,stairs);
...
...
for i:=1 to N do
if random(2)=0 then
subset[i]:=0
else
subset[i]:=stairs[i];
result:=step(subset);
...
The problem
 C/C++ example:
 #include
"libconq.h"
 int stairs[2001];
 int subset[2001];
 int i,N,result;
 ...
start(&N, stairs);
...
for (i=1;i<=N;i++)
if (rand()%2==0)
subset[i]=0;
else
subset[i]=stairs[i];
result=step(subset);
...
The problem
You have to link the library to your
program – by uses libconq; in
FreePascal and by #include "libconq.h“
in C/C++, where you have to compile
your program by adding libconq.c to the
compiler arguments.
The problem
An example of the game
You: Library:
start(N,stairs) N=8, stairs=(0,1,1,0,3,3,4,0)
step((0,1,0,0,1,0,1,0)) returns 2(0,0,1,0,2,3,3,0,0)
step((0,1,0,0,0,1,0,0)) returns 2(0,0,0,2,3,2,0,0,0)
step((0,0,0,3,2,0,0,0)) returns 1(0,0,0,3,2,0,0,0,0)
step((0,0,2,0,0,0,0,0)) returns 2(0,0,1,2,0,0,0,0,0)
step((0,1,0,0,0,0,0,0)) returns 2(0,0,2,0,0,0,0,0,0)
step((0,1,0,0,0,0,0,0)) no return: you won
The problem
The file libconq.dat for the example
above
would look like this:
8
01103340
Solution
Let’s try to tell somehow how good a
position is. If we have two soldiers on the
same stair (and no other soldiers), in the
next round we will have at most only one
soldier but one stair higher. In this way,
one soldier on the stair S is equivalent to
two soldiers on the stairs S+1.
Solution
From now on a soldier on the stair S will
have the value 2N-S. The value of a
position will be the sum of the values of
all the soldiers. Note that all positions,
where the Conqueror has won, have the
value at least 2N-1 because there is a
soldier on the stair number 1.
Solution
25-1
1
2*25-2
2
1
4
2
A soldier on stair S
has value 2N-S
4*25-3
8*25-4
8
3
16
4
5
16*25-5
Solution
n1*25-2
n1
1
n2
2
n2*25-3
n3
3
4
5
A position’s value = sum (all soldiers)
n3*25-4
Solution
 Losing positions
If the value of the position is less than 2N1 and the commandant plays optimally,
the Conqueror will lose.
Solution
 Proof
If the value is less than 2N-1 , the Conqueror
didn’t win yet. Let’s take a look at one
round of the game. The Conqueror
divides his soldiers in some way. The
commandant will choose this group to
stay and the other to leave.
Solution
When any soldier moves up one stair, his
value doubles. Therefore the value of
the new position will be less than 2*2N2=2N-1 and the number of the soldier will
decrease. There is a finite number of
soldiers, and so the game ends in a
finite number of moves. The value of a
position will always be less than 2N-1,
also at the end there will be no soldiers
and the Conqueror will lose.
Solution
 Losing position
smaller
<2N-1
larger
<2*2N-2=2N-1
……………………………..
Solution
 Winning position
If the value of the position is at least than
2N-1 and the Conqueror plays optimally, he
will win.
Solution
 Proof
The Conqueror has to divide the soldiers
into two groups so that the value of each
group will be at least 2N-2. Then
regardless of the commandant’s choice
the new position will again have the
value at least 2N-1. and there will be less
soldiers than before.
Solution
There is a finite number of soldiers, and so
the game will end in a finite number of
moves. At the end of the game the value
of the position will be at least 2N-1. This
means that some of the soldiers has to
stand on the stair 1 and the Conqueror
won. We only need to show, that the
Conqueror can always divide the soldiers
in the way described above.
Solution
 Lemma: Let a1,…aM(2N-2
>=a1>=…>=aM, M>=2) be powers of
two with sum(ai,1<=i<=M) >= 2N-2.
Then for some K holds sum(ai,1<=i<=k)
= 2N-2.
Solution
 Example
24>=23>= 23>= 22>=22 (M=4, N=6)
23 + 23 + 22 +22 > 24
Then K=2, 23 + 23 = 24
Solution
 Proof
Induction on M. For M=2 the lemma holds.
2N-2 >= a1 >= a2
a1 + a2 >= 2N-2
Either a1= 2N-2(k=1)
or (a1 = a2 = 2N-3 and a1 + a2 = 2N-2(k=2)
Solution
 Now let M>2 and
 sum(ai,1<=i<=M) > 2N-2
 Because ais are multiple of 2,
sum(ai,1<=i<=M) = k1aM
2N-2 = k2aM
Therefore sum(ai,1<=i<=M) >= 2N-2+aM
Then sum(ai,1<=i<=M-1) >=2N-2
We may apply the induction assumption.
Solution
 From the lemma we get that if the sum of
the soldiers’ values is at least 2N-1, we
may select the first (eg. Closet to the top
of the staircase) few of them so that the
sum of their values will be exactly 2N-2 .
The Conqueror may also divide his
soldiers into these two groups.
Solution
3
2N-3
4
2N-4
4
2N-4
5
2N-5
……
……
2N-2
Solution
 If we are in a losing position, we choose
an empty set and loose instantly. If we
are in a winning position, we find the
place where to split the soldiers by
adding the values of soldiers on stairs
1,2,…until the value reaches 2N-2.
本节课小结





作业总结 - 1008
作业总结 - 1013
何林冬令营报告 – 称球问题
自学及讨论 – 征服者
作业
作业
 1016
 1048