射击问题
在一个靶子的不同区域分别标记有从1环到10环的不同分值,某人在一次射击比赛中用10发子弹打出了90环的成绩,问这10次射击取得的分值有哪些可能?
设10次射击分别得到的分数为X1, X2, …, X10,则问题就是生成线性方程
X1+X2+…+X10=90 (10≥X1, X2, …, X10≥0)
的各种可能的解。
一般地,我们来解决n个变量的和为Sum,且每一个变量的取值范围在LB~UB之间的问题,即:
X1+X2+…+Xn=Sum (UB≥X1, X2, …, Xn≥LB)
(1)
由于对n个[LB, UB]之间的元素,其和的最小值为n*LB,最大值为n*UB,显然,Sum必须在n*LB~n*UB之间取值。
我们利用递归的思想来解决上述问题,首先,我们看变量Xn所有可能的取值:对于给定的Xn,问题变为:
X1+X2+…+Xn-1=Sum-Xn (UB≥X1, X2, …, Xn-1≥LB)
(2)
问题(2)有解,必须
(n-1)LB≤Sum-Xn≤(n-1)UB
即
Sum-(n-1)UB≤Xn≤Sum-(n-1)LB
同时,由于
LB≤Xn≤UB
因此,Xn的取值范围为:
max(LB, Sum-(n-1)UB)≤Xn≤
min(UB,Sum-(n-1)LB)
问题求解的Prolog程序如下:
domains
ilist=integer*
predicates
nondeterm solver(integer, ilist, integer, integer, integer)
nondeterm max(integer, integer, integer)
nondeterm min(integer, integer, integer)
nondeterm for(integer, integer, integer)
clauses
solver(1, [Sum], Sum, LB, UB):-
Sum >= LB,
Sum <= UB.
solver(N, [X|L], Sum, LB, UB):-
N > 1,
N1 = N-1,
A = Sum - N1*UB,
max(LB, A, P),
B = Sum - N1*LB,
min(UB, B, Q),
Q >= P,
for(X, P, Q),
Sum1 = Sum - X,
solver(N1, L, Sum1, LB, UB).
max(X,Y,Y):-X <= Y, !.
max(X, Y, X):-X > Y.
min(X,Y,X):-X <= Y, !.
min(X, Y, Y):-X > Y.
for(Low, Low, Up):-Low <= Up.
for(X, Low, Up):-
Low < Up,
Low1 = Low + 1,
for(X, Low1, Up).
goal
solver(10, L, 90, 0, 10),
write(L), nl,
fail.
执行目标可以找到问题大量的解,其中前面3个解为:
[0,10,10,10,10,10,10,10,10,10]
[1,9,10,10,10,10,10,10,10,10]
[1,10,9,10,10,10,10,10,10,10]
最后3个解为:
[10,10,10,10,10,10,10,10,8,2]
[10,10,10,10,10,10,10,10,9,1]
[10,10,10,10,10,10,10,10,10,0]
~~~~~~~~~~~~~~~~~~~
如果不考虑射击分值的次序,而只考虑各种分值的不同组合,问题的求解将产生变化。
假设在10次射击中,得0分X0次,得1分X1次,…,得10分X10次,则问题可以转化为求线性不定方程
0*X0+1*X1+…+9*X9+10*X10=90
X0+X1+…+X9+X10=10
一般地,我们求不定方程:
0*X0+1*X1+…+(n-1)*Xn-1+n*Xn=Sum (1)
X0+X1+…+Xn-1+Xn=Times (2)
的非负整数解。
有(1),(2)
Xn≤
min(Times,[Sum/n])
因此,对于选定的Xn,问题变为:
0*X0+1*X1+…+(n-1)*Xn-1=Sum-n*Xn (3)
X0+X1+…+Xn-1 =Times-Xn (4)
基于上述问题的递推关系,可以得到Prolog程序:
domains
ilist=integer*
predicates
nondeterm solver(integer, ilist, integer, integer)
nondeterm min(integer, integer, integer)
nondeterm for(integer, integer, integer)
clauses
solver(0, [Times], 0, Times).
solver(N, [X|L], Sum, Times):-
N > 0,
N1 = N-1,
P = Sum div N,
min(Times, P, Q),
for(X, 0, Q),
Sum1 = Sum - N*X,
Times1 = Times - X,
solver(N1, L, Sum1, Times1).
min(X,Y,X):-X <= Y, !.
min(X, Y, Y):-X > Y.
for(Low, Low, Up):-Low <= Up.
for(X, Low, Up):-
Low < Up,
Low1 = Low + 1,
for(X, Low1, Up).
goal
solver(10, L, 90, 10),
write(L), nl,
fail.
执行目标找到问题的全部42个解:
[0,10,0,0,0,0,0,0,0,0,0]
[1,8,1,0,0,0,0,0,0,0,0]
[2,6,2,0,0,0,0,0,0,0,0]
[2,7,0,1,0,0,0,0,0,0,0]
[3,4,3,0,0,0,0,0,0,0,0]
[3,5,1,1,0,0,0,0,0,0,0]
[3,6,0,0,1,0,0,0,0,0,0]
[4,2,4,0,0,0,0,0,0,0,0]
[4,3,2,1,0,0,0,0,0,0,0]
[4,4,0,2,0,0,0,0,0,0,0]
[4,4,1,0,1,0,0,0,0,0,0]
[4,5,0,0,0,1,0,0,0,0,0]
[5,0,5,0,0,0,0,0,0,0,0]
[5,1,3,1,0,0,0,0,0,0,0]
[5,2,1,2,0,0,0,0,0,0,0]
[5,2,2,0,1,0,0,0,0,0,0]
[5,3,0,1,1,0,0,0,0,0,0]
[5,3,1,0,0,1,0,0,0,0,0]
[5,4,0,0,0,0,1,0,0,0,0]
[6,0,2,2,0,0,0,0,0,0,0]
[6,0,3,0,1,0,0,0,0,0,0]
[6,1,0,3,0,0,0,0,0,0,0]
[6,1,1,1,1,0,0,0,0,0,0]
[6,1,2,0,0,1,0,0,0,0,0]
[6,2,0,0,2,0,0,0,0,0,0]
[6,2,0,1,0,1,0,0,0,0,0]
[6,2,1,0,0,0,1,0,0,0,0]
[6,3,0,0,0,0,0,1,0,0,0]
[7,0,0,2,1,0,0,0,0,0,0]
[7,0,1,0,2,0,0,0,0,0,0]
[7,0,1,1,0,1,0,0,0,0,0]
[7,0,2,0,0,0,1,0,0,0,0]
[7,1,0,0,1,1,0,0,0,0,0]
[7,1,0,1,0,0,1,0,0,0,0]
[7,1,1,0,0,0,0,1,0,0,0]
[7,2,0,0,0,0,0,0,1,0,0]
[8,0,0,0,0,2,0,0,0,0,0]
[8,0,0,0,1,0,1,0,0,0,0]
[8,0,0,1,0,0,0,1,0,0,0]
[8,0,1,0,0,0,0,0,1,0,0]
[8,1,0,0,0,0,0,0,0,1,0]
[9,0,0,0,0,0,0,0,0,0,1]
例如,第一个解[0,10,0,0,0,0,0,0,0,0,0]对应10次都是9环;解[4,3,2,1,0,0,0,0,0,0,0]对应4次10环,3次9环,2次8环,1次7环,而
4×10+3×9+2×8+1×7=90
最后一个解[9,0,0,0,0,0,0,0,0,0,1]对应9次10环,1次脱靶。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
对于第二个问题中的一个解[Xn,Xn-1,…,X1,X0],将对应第一个问题中
(Xn+Xn-1+…+X1+X0)!/ Xn!Xn-1!…X1!X0!
个解。例如,[4,3,2,1,0,0,0,0,0,0,0]是问题二的一个解,它对应问题一的10!/4!3!2!=12600个解。问题一所有可能的解的个数为92378。下面的表采用excel编制,其中解的个数一栏=FACT(SUM(A1:K1))/(FACT(A1)*FACT(B1)*FACT(C1)*FACT(D1)*FACT(E1)*FACT(F1)*FACT(G1)*FACT(H1)*FACT(I1)*FACT(J1)*FACT(K1)),其中FACT(X)为X的阶乘函数。
序号
|
问题二的解
|
对应问题一的解数
| ||||||||||
1
|
0
|
10
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
1
|
2
|
1
|
8
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
90
|
3
|
2
|
6
|
2
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
1260
|
4
|
2
|
7
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
360
|
5
|
3
|
4
|
3
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
4200
|
6
|
3
|
5
|
1
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
5040
|
7
|
3
|
6
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
840
|
8
|
4
|
2
|
4
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
3150
|
9
|
4
|
3
|
2
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
12600
|
10
|
4
|
4
|
0
|
2
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
3150
|
11
|
4
|
4
|
1
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
6300
|
12
|
4
|
5
|
0
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
1260
|
13
|
5
|
0
|
5
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
252
|
14
|
5
|
1
|
3
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
5040
|
15
|
5
|
2
|
1
|
2
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
7560
|
16
|
5
|
2
|
2
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
7560
|
17
|
5
|
3
|
0
|
1
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
5040
|
18
|
5
|
3
|
1
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
5040
|
19
|
5
|
4
|
0
|
0
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
1260
|
20
|
6
|
0
|
2
|
2
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
1260
|
21
|
6
|
0
|
3
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
840
|
22
|
6
|
1
|
0
|
3
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
840
|
23
|
6
|
1
|
1
|
1
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
5040
|
24
|
6
|
1
|
2
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
2520
|
25
|
6
|
2
|
0
|
0
|
2
|
0
|
0
|
0
|
0
|
0
|
0
|
1260
|
26
|
6
|
2
|
0
|
1
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
2520
|
27
|
6
|
2
|
1
|
0
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
2520
|
28
|
6
|
3
|
0
|
0
|
0
|
0
|
0
|
1
|
0
|
0
|
0
|
840
|
29
|
7
|
0
|
0
|
2
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
360
|
30
|
7
|
0
|
1
|
0
|
2
|
0
|
0
|
0
|
0
|
0
|
0
|
360
|
31
|
7
|
0
|
1
|
1
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
720
|
32
|
7
|
0
|
2
|
0
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
360
|
33
|
7
|
1
|
0
|
0
|
1
|
1
|
0
|
0
|
0
|
0
|
0
|
720
|
34
|
7
|
1
|
0
|
1
|
0
|
0
|
1
|
0
|
0
|
0
|
0
|
720
|
35
|
7
|
1
|
1
|
0
|
0
|
0
|
0
|
1
|
0
|
0
|
0
|
720
|
36
|
7
|
2
|
0
|
0
|
0
|
0
|
0
|
0
|
1
|
0
|
0
|
360
|
37
|
8
|
0
|
0
|
0
|
0
|
2
|
0
|
0
|
0
|
0
|
0
|
45
|
38
|
8
|
0
|
0
|
0
|
1
|
0
|
1
|
0
|
0
|
0
|
0
|
90
|
39
|
8
|
0
|
0
|
1
|
0
|
0
|
0
|
1
|
0
|
0
|
0
|
90
|
40
|
8
|
0
|
1
|
0
|
0
|
0
|
0
|
0
|
1
|
0
|
0
|
90
|
41
|
8
|
1
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
1
|
0
|
90
|
42
|
9
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
0
|
1
|
10
|
问题一解的总数
|
92378
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~