射击问题求解程序-Prolog

 
射击问题
在一个靶子的不同区域分别标记有从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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值