從itpub看來的一道組合題

lt發表於2017-04-05

有人在 itpub論壇(http://www.itpub.net/thread-2086095-1-1.html) 提出如下問題

現有兩個表:a表,c表。
a表裡存有7碼組合,大約有六百多萬條。
c表裡有13條記錄,每條記錄是5碼的組合:
                 10 16 19 20 34 
                 10 14 19 25 32 
                 8 17 25 33 34
                 6 18 22 23 33
                 1 6  14 17 29
                 21 22 24 29 34
                 2  16 17 30 32
                 2  13 14 18 29
                 15 22 23 25 34
                6  12 21 26 29 
                14 17 22 30 33
                1  4  9  18 22
                13 15 16 32 34
從a表選出與c表中的每一個組合的相同數等於1的7碼 組合。
比如從a表選出一組:4 13 17 19 21 23 28 
這一組與c表的每一個組合的相同數都是一個數,與第一組的相同數是19,與第二組的想同數是19,與第三組的相同數是17,與第四組的相同數是23,與第五組的相同數是17,與第六組的相同數是21,與第七組的相同數是17,與第八組的相同數是13,與第九組的相同數是 23,與第十組的相同數是21,與第十一組的相同數是17,與第十二組的相同數是4,與第十三組的相同數是13,它們的相同個數都是1。
要求從a表選出符合這樣條件的7碼組合。

他的問題我已經用bitand位操作解決了。

with c as
(select power(2,10)+power(2,16)+power(2,19)+power(2,20)+power(2,34) code1 from dual),
a as(select power(2,19) code from dual
union select power(2,31) code from dual
union select power(2,10)+power(2,16) code from dual)
select code from a,c
where 
bitand(code,code1) in (select power(2,level) from dual connect by level<=63)

分析
感覺這種組合是可以完全列舉出來的,看有什麼辦法。
設13種組合分別是集合A-N,如果集合X符合要求,那麼(X &A)|(X &B)······| (X &N)=X,且每個括號都是單個元素。
把1~34各數在13個組合中的存在情況分類,找出允許的值,然後依次確定第1~7個數,如果中途超過,則轉下一個

c=[
10 16 19 20 34
10 14 19 25 32
8 17 25 33 34
6 18 22 23 33
1 6  14 17 29
21 22 24 29 34
2  16 17 30 32
2  13 14 18 29
15 22 23 25 34
6  12 21 26 29
14 17 22 30 33
1  4  9  18 22
13 15 16 32 34
];


d=Array{Array{Int}}(34);
p=zeros(Int,34);
for x in 1:34
  #d[x]=Array{Int}(34)
  #map(n->d[x][n]=0,1:34);
  d[x]=zeros(Int,34)
  for i in 1:13
    for j in 1:5
      #if x==c[(i-1)*5+j] d[x][j]=i end
      if x==c[i,j] p[x]=p[x]+1;d[x][p[x]]=i end
    end
  end
end
for x in 1:34
  if p[x]>0 println(x)
  end
end

從1開始的過程

julia> dt=Dict{Int,Int}()
Dict{Int32,Int32} with 0 entries

julia> map(x->if p[x]>0 dt[x]=1 end,1:34)
34-element Array{Any,1}:
 1
 1
  nothing
 1
  nothing

julia> dt
Dict{Int32,Int32} with 27 entries:
  32 => 1
  25 => 1
  19 => 1
  33 => 1
  24 => 1

julia> n=Dict{Int,Int}()
Dict{Int32,Int32} with 0 entries

julia> n[1]=pop!(dt,1)
1

julia> d[1]
34-element Array{Int32,1}:
  5
 12

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[1][1],1:5])
5-element Array{Any,1}:
  nothing
 1
 1
 1
 1

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[1][2],1:5])
5-element Array{Any,1}:
  nothing
 1
 1
 1
 1

julia> dt
Dict{Int32,Int32} with 18 entries:
  32 => 1
  25 => 1
  19 => 1
  33 => 1
  24 => 1
  15 => 1
  10 => 1
  20 => 1
  26 => 1
  2  => 1
  16 => 1
  12 => 1
  13 => 1
  8  => 1
  23 => 1
  21 => 1
  30 => 1
  34 => 1

julia> n[2]=pop!(dt,2)
1

julia> d[2]
34-element Array{Int32,1}:
 7
 8

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[2][1],1:5])
5-element Array{Any,1}:
  nothing
 1
  nothing
 1
 1

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[2][2],1:5])
5-element Array{Any,1}:
  nothing
 1
  nothing
  nothing
  nothing

julia> dt
Dict{Int32,Int32} with 13 entries:
  25 => 1
  19 => 1
  33 => 1
  24 => 1
  15 => 1
  10 => 1
  20 => 1
  26 => 1
  12 => 1
  8  => 1
  23 => 1
  21 => 1
  34 => 1

julia> n
Dict{Int32,Int32} with 2 entries:
  2 => 1
  1 => 1

julia> n[8]=pop!(dt,8)
1

julia> d[8]
34-element Array{Int32,1}:
 3

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[8][1],1:5])
5-element Array{Any,1}:
  nothing
  nothing
 1
 1
 1

julia> n[10]=pop!(dt,10)
1

julia> n
Dict{Int32,Int32} with 4 entries:
  10 => 1
  8  => 1
  2  => 1
  1  => 1

julia> d[10]
34-element Array{Int32,1}:
 1
 2

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[10][1],1:5])
5-element Array{Any,1}:
  nothing
  nothing
 1
 1
  nothing

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[10][2],1:5])
5-element Array{Void,1}:
 nothing
 nothing
 nothing
 nothing
 nothing

julia> dt
Dict{Int32,Int32} with 6 entries:
  24 => 1
  15 => 1
  26 => 1
  12 => 1
  23 => 1
  21 => 1

julia> n[12]=pop!(dt,12)
1

julia> d[12]
34-element Array{Int32,1}:
 10

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[12][1],1:5])
5-element Array{Any,1}:
  nothing
  nothing
 1
 1
  nothing

julia> dt
Dict{Int32,Int32} with 3 entries:
  24 => 1
  15 => 1
  23 => 1

julia> n
Dict{Int32,Int32} with 5 entries:
  10 => 1
  12 => 1
  8  => 1
  2  => 1
  1  => 1

julia> n[15]=pop!(dt,15)
1

julia> d[15]
34-element Array{Int32,1}:
  9
 13

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[15][1],1:5])
5-element Array{Any,1}:
  nothing
  nothing
 1
  nothing
  nothing

julia>  map(x->if haskey(dt,x) pop!(dt,x) end,c[d[15][2],1:5])
5-element Array{Void,1}:
 nothing
 nothing
 nothing
 nothing
 nothing

julia> dt
Dict{Int32,Int32} with 1 entry:
  24 => 1

julia> n
Dict{Int32,Int32} with 6 entries:
  15 => 1
  10 => 1
  12 => 1
  8  => 1
  2  => 1
  1  => 1

julia> n[24]=pop!(dt,24)
1

julia> n
Dict{Int32,Int32} with 7 entries:
  24 => 1
  15 => 1
  10 => 1
  12 => 1
  8  => 1
  2  => 1
  1  => 1

上述步驟有些繁瑣,而且選擇下一個數有盲目性。其實每個數字都有互斥的數,這個排除應該高效一點。

ca=Array{Dict{Int,Int}}(34);

map(z->(ca[z]=Dict{Int,Int}();map(x->ca[z][x]=1,1:34)),1:34);

for i in 1:13
    for j in 1:5
      map(x->if haskey(ca[c[i,j]],x) pop!(ca[c[i,j]],x) end,c[i,1:5]);
    end 
end

function f(d::Dict{Int,Int},n::Int,m::Int,c::Int) #n last element, m set size
d1=d;
c1=c;
if  length(d)>=m 
 if c1!=13 println(d) end; # no result of c1==13
 return 
else
for i in ca[n] 
  #println(i[1]) #key of dict
  if !haskey(d1,i[1]) 
    d1[i[1]]=1;
      f(d1,i[1] ,m,c1+ countnz(d[i[1]]))
    pop!(d1,i[1]);
  end
end
end
end

d0=Dict{Int,Int}();
d0[1]=1;
f(d0,1,4, countnz(d[1]))
#f(d0,1,7, countnz(d[1])) #about 5 minues with no result

上述程式在不規定出現總次數時能輸出,規定13次則無輸出,錯在d的區域性變數覆蓋了全域性變數,countnz(d[i[1]] 實際上成了已選數,而不是組數。還有其他條件也沒有寫。 用Dict查詢比較浪費,改用陣列實現,實際上就是用2進位制位來判斷已用和未用

c=[
10 16 19 20 34
10 14 19 25 32
8 17 25 33 34
6 18 22 23 33
1 6  14 17 29
21 22 24 29 34
2  16 17 30 32
2  13 14 18 29
15 22 23 25 34
6  12 21 26 29
14 17 22 30 33
1  4  9  18 22
13 15 16 32 34
];


d=Array{Array{Int}}(34);
p=zeros(Int,34);
for x in 1:34
  #d[x]=Array{Int}(34)
  #map(n->d[x][n]=0,1:34);
  d[x]=zeros(Int,34)
  for i in 1:13
    for j in 1:5
      #if x==c[(i-1)*5+j] d[x][j]=i end
      if x==c[i,j] p[x]=p[x]+1;d[x][p[x]]=i end
    end
  end
end
for x in 1:34
  if p[x]>0 println(x)
  end
end

da=Array{Array{Int}}(34);

map(z->(da[z]=1:34;map(x->da[z][x]=1,1:34)),1:34);

for i in 1:13
    for j in 1:5
      map(x->da[c[i,j]][x]=0,c[i,1:5]);
    end
end

function pf(d::Array{Int})
  map(x->if d[x]==1 print(" ",x) end ,1:34)
  println("");
end

function fun(d::Array{Int},f::Array{Int},n::Int,m::Int,c::Int) #n last element, m set size
  #d1=d;
  d1=Array{Int}(34)
  copy!(d1,d)
  if  countnz(d)>=m
    if c==13 pf(d) end; # no result of c1==13
    return
  end
  #println(f)
  for i in n:34 #ca[n]
    #println(i[1]) #key of dict
    if sum(da[i])<34 && f[i]==1 #can use
      d1[i]=1;
      f1=(f .& da[i]) #pa1 is array of pair
      #println("\nd1",d1,"\nf1",f1)
      if countnz(f1)>0
        #println("i=",i);
        fun(d1,f1,i ,m,c+ p[i]);
      end
      d1[i]=0;
    end
  end
end

a0=zeros(Int,34);
a0[1]=1;
fun(a0,da[1],1,2,(p[1]))
@time fun(a0,da[1],1,6,(p[1]))
@time fun(a0,da[1],1,7,(p[1]))

@time map(x->(if sum(da[x])<34 a0=zeros(Int,34);a0[x]=1;fun(a0,da[x],x,7,(p[1]))end),1:34)

執行結果

julia> @time fun(a0,da[1],1,6,(p[1]))
 1 2 10 15 21 33
 1 2 15 19 21 33
  0.064445 seconds (35.56 k allocations: 1.228 MiB)

julia> @time fun(a0,da[1],1,7,(p[1]))
 1 2 10 12 15 24 33
 1 2 10 15 24 26 33
 1 2 12 15 19 24 33
 1 2 15 19 24 26 33
 1 8 10 13 21 23 30
 1 8 13 19 21 23 30
  0.093311 seconds (38.09 k allocations: 1.314 MiB)

相關文章