图片中给出的是无线电平均标号的定义,以及两条路笛卡尔乘积图的示意图,请你根据定义求出两条路的无限电平...
생성일: 2026년 6월 18일
답변에 사용된 모델 GPT-5.5 Thinking by Chat01
생성일: 2026년 6월 18일
답변에 사용된 모델 GPT-5.5 Thinking by Chat01
图片中给出的是无线电平均标号的定义,以及两条路笛卡尔乘积图的示意图,请你根据定义求出两条路的无限电平均标号数,最后的结果我想要的是确切的数值以及表达式,而不是范围区间,并给出严谨的上下届证明,最后结果以PDF格式显现
pythonfrom functools import lru_cache def solve_ladder(n, M, want_assignment=False): verts=[(r,c) for c in range(n) for r in range(2)] # columns order N=len(verts); d=n dist=[[abs(c1-c2)+(r1!=r2) for (r2,c2) in verts] for (r1,c1) in verts] # recursive: process labels 1..M, assigned list vertex per used label (dict tuple) # state: label, used mask, tuple of used assignments maybe need constraints with labels # Since constraints depend on previous labels values and vertices, need store assigned pairs. # backtracking with pruning assigned=[] usedmask=0 # order vertices maybe extremes first allmask=(1<<N)-1 # For each l and previous (p,vp), compute allowed v if distance cond. def ok_pair(l,v,p,vp): return dist[v][vp] + ((l+p+1)//2) >= n+1 # ceil best=None # symmetrical fix label 1 to one vertex? Since automorphisms, label 1 can be top-left? maybe only for existence? Not necessarily any vertex can be moved to one of orbits by dihedral. Ladder automorphism transposes rows and reverses columns; vertices in column c and n-1-c same orbit. Label1 likely must be near end? But no fix. from functools import lru_cache # Need memo on l, usedmask, assigned tuple? constraints depend assigned labels/positions. Can't compress. calls=0 def rec(l, usedmask, ass): nonlocal best,calls calls+=1 usedcnt=usedmask.bit_count() if usedcnt==N: best=ass return True if l>M: return False if usedcnt + (M-l+1) < N: return False # Try skipping l maybe, but only if enough left and maybe skip small to satisfy. But for minimizing M, skipping low labels common. # Try assigning l first? It might be necessary to use many labels. # Generate allowed vertices allowed=[] for v in range(N): if not (usedmask>>v)&1: good=True for p,vp in ass: if not ok_pair(l,v,p,vp): good=False; break if good: allowed.append(v) # heuristic: if l small, assign restricted vertices. Try allowed ordered by extremes # But also skip option. # Branch choose assign l or skip. Use memo? for v in allowed: if rec(l+1, usedmask| (1<<v), ass+((l,v),)): return True # skip if rec(l+1, usedmask, ass): return True return False res=rec(1,0,tuple()) if want_assignment and res: return True, [(l, verts[v]) for l,v in best], calls return res,calls for n in range(1,8): N=2*n for M in range(N, 5*n+5): ok,_=solve_ladder(n,M) if ok: print(n, M) break
pythonfor n in range(8,11): for M in range(2*n, 4*n): ok,calls=solve_ladder(n,M) if ok: print("n",n,"M",M,"calls",calls) break # print(n,M,calls)
pythonfor n in range(5,11): M=None for m in range(2*n,4*n): ok,calls=solve_ladder(n,m) if ok: M=m; break ok,ass,calls=solve_ladder(n,M,True) print("n",n,"M",M) # display grid with label or . grid=[["." for c in range(n)] for r in range(2)] for l,(r,c) in ass: grid[r][c]=str(l) for r in range(2): print(grid[r]) print("used labels", [l for l,v in ass], "skipped", [i for i in range(1,M+1) if i not in [l for l,v in ass]]) print()
pythonimport sympy as sp n,M=sp.symbols('n M', integer=True, positive=True) # max weighted sum: 2n labels from 1..M; assign largest 2n-4 to deg 3, next 4 to deg 2. # Sum largest k labels up to M = k*(2M-k+1)/2 k=2*n-4 sum_largest_k=k*(2*M-k+1)/2 sum_next4=4*(2*M-k-4+1)/2 # labels M-k-3..M-k max_weight=3*sum_largest_k+2*sum_next4 req=(3*n-2)*(2*n-1) sp.expand(max_weight), sp.solve_univariate_inequality(sp.expand(max_weight-req)>=0,M)
pythonimport sympy as sp n,M=sp.symbols('n M') k=2*n-4 sum_largest_k=k*(2*M-k+1)/2 sum_next4=4*(2*M-k-4+1)/2 max_weight=sp.expand(3*sum_largest_k+2*sum_next4) req=sp.expand((3*n-2)*(2*n-1)) print(max_weight) print(req) print(sp.expand(max_weight-req)) print(sp.solve(sp.Eq(max_weight-req,0),M))
pythondef pair_sum_lower_ladder(n): verts=[(r,c) for r in range(2) for c in range(n)] total=0 count=0 from itertools import combinations for u,v in combinations(range(2*n),2): r1,c1=verts[u]; r2,c2=verts[v] t=abs(c1-c2)+(r1!=r2) total+=2*n+1-2*t count+=1 return total for n in range(2,11): total=pair_sum_lower_ladder(n) print(n,total, total/(2*n-1)) # max sum labels with span M = n*(2*M-2*n+1). Lower yields import math M=math.ceil((total/(2*n-1)/n +2*n-1)/2) # solve n(2M-2n+1)>=total/(2n-1) print("Mlb",M, "formula", math.ceil((8*n-8)/3))
pythonfrom itertools import combinations def packing_ladder(n,r): # mutual distance >= r+1 verts=[(row,c) for c in range(n) for row in range(2)] N=2*n conflict=[[False]*N for _ in range(N)] for i in range(N): for j in range(i+1,N): d=abs(verts[i][1]-verts[j][1])+(verts[i][0]!=verts[j][0]) if d<=r: conflict[i][j]=conflict[j][i]=True # brute force max independent in conflict for small n best=0 bestset=None for mask in range(1<<N): # too large for 20 maybe ok 1M if mask.bit_count()<=best: continue ok=True for i in range(N): if (mask>>i)&1: # check only j>i for j in range(i+1,N): if (mask>>j)&1 and conflict[i][j]: ok=False; break if not ok: break if ok: best=mask.bit_count(); bestset=mask return best for r in range(1,8): print("r",r, [packing_ladder(n,r) for n in range(2,13)])
pythonimport math def q_packing_lb(n): vals=[] for r in range(1,n+1): vals.append(n-r-math.ceil(n/r)) return max(0,max(vals)), vals for n in range(1,31): q,_=q_packing_lb(n) print(n,q, "Mlb",2*n+q)
python# Re-define more efficient solver with candidates and memo. from functools import lru_cache def feasible_ladder(n, M, find=False, time_limit_nodes=1000000): verts=[(r,c) for c in range(n) for r in range(2)] N=2*n dist=[[abs(c1-c2)+(r1!=r2) for (r2,c2) in verts] for (r1,c1) in verts] # precompute allowed mask for label l given previous label p and vertex vp: vertices v compatible comp={} for l in range(1,M+1): for p in range(1,l): req=n+1-((l+p+1)//2) # need dist>=req masks=[] for vp in range(N): mask=0 for v in range(N): if v!=vp and dist[v][vp]>=req: mask |= 1<<v masks.append(mask) comp[(p,l)]=masks full=(1<<N)-1 # symmetry for first used
pythonresults={} for n in range(1,31): # use previous for n small? lb=2*n+q_packing_lb(n)[0] for M in range(lb, 4*n): # upper hopefully ok,nodes,ass=feasible_ladder(n,M,time_limit_nodes=1000000) if ok is None: print("timeout",n,M,nodes) break if ok: results[n]=M print(n,M,"q",M-2*n,"lbq",q_packing_lb(n)[0],"nodes",nodes) break if n not in results: print("not found n",n) break
pythonfor n in [12,13,14,15,20,25]: M=results[n] ok,nodes,ass=feasible_ladder(n,M,find=True,time_limit_nodes=1000000) print("n",n,"M",M,"p",3*n-M,"skips",[i for i in range(1,M+1) if i not in [l for l,v in ass]][:50]) grid=[["." for c in range(n)] for r in range(2)] for l,(r,c) in ass: grid[r][c]=l for r in range(2): print(" ".join(f"{grid[r][c]:2}" for c in range(n))) print()
pythonfrom functools import lru_cache def feasible_deficits(t,n,find=False): verts=[(r,c) for c in range(n) for r in range(2)] N=2*n dist=[[abs(c1-c2)+(r1!=r2) for (r2,c2) in verts] for (r1,c1) in verts] # assign deficits t,t-1,...? Larger more restrictive. Deficit labels are values 1..t. order=list(range(t,0,-1)) # Fix largest deficit t maybe at left/right? Use symmetry row0 maybe, and column <= middle? ass={} used=0 nodes=0 def rec(idx, usedmask, assignments): nonlocal nodes nodes+=1 if idx==len(order): return assignments x=order[idx] # candidate all vertices not used meeting constraints with assigned deficits candidates=[] for v in range(N): if usedmask>>v &1: continue ok=True for y,vy in assignments.items(): req=(x+y)//2 +1 # floor((x+y)/2)+1 if dist[v][vy] < req: ok=False;break if ok: candidates.append(v) # symmetry for first if idx==0: candidates=[v for v in candidates if verts[v][0]==0 and verts[v][1]<= (n-1)//2] # order by near center/ends? candidates.sort(key=lambda v: abs(verts[v][1]-(n-1)/2)) for v in candidates: res=rec(idx+1, usedmask|1<<v, {**assignments,x:v}) if res is not None: return res return None res=rec(0,0,{}) if find and res is not None: return True,{x:verts[v] for x,v in res.items()},nodes return res is not None,nodes def W_deficits(t): for n in range(1,100): ok,_=feasible_deficits(t,n) if ok: return n for t in range(1,16): w=W_deficits(t) print(t,w)
pythonimport math def W(t): if t<=0: return 0 if t==1: return 1 if t==2: return 2 if t%2==0: s=t//2 return 2*s*s-2*s+3 else: s=(t-1)//2 return 2*s*s+2 def A(n): t=0 while W(t+1)<=n: t+=1 return t for n in range(1,31): M=max(2*n,3*n-A(n)-1) print(n,A(n),M)
pythonfor n in range(3,200): a=A(n) b=math.floor(1+math.sqrt(2*n-4)) if a!=b: print("mismatch",n,a,b,W(a),W(a+1)); break else: print("all ok")
python# implement a reliable coordinate construction manually maybe find one for t up to 9 using previous function but trust? Need not. def find_deficit_assignment(t): n=W(t) ok,assign,nodes=feasible_deficits(t,n,find=True) return assign for t in range(1,10): assign=find_deficit_assignment(t) print("t",t,"W",W(t),assign) # sort by deficit # grid n=W(t) grid=[["." for _ in range(n)] for _ in range(2)] for x,(r,c) in assign.items(): grid[r][c]=str(x) for row in grid: print(" ".join(f"{v:>2}" for v in row)) print()
pythonimport itertools, math def min_path_weight(t): best=10**9; bestp=None for perm in itertools.permutations(range(1,t+1)): s=sum((perm[i]+perm[i+1])//2 for i in range(t-1)) if s<best: best=s;bestp=perm return best,bestp for t in range(1,9): print(t, min_path_weight(t), "W-1", W(t)-1)
pythondef construction_perm(t): if t==1: return [1] if t==2: return [2,1] # or # pattern for t: # for t=5 min path [3,2,1,4,5] # for t=7 [5,2,1,4,3,6,7] # for t=9 [7,2,1,4,3,6,5,8,9] maybe perm=[t-2 if t%2==1 else t-1] # endpoint largest-1 for odd, t-1 for even # Actually for t=9 start7; yes t-2. # then pairs 2,1,4,3,6,5,... up to t-3? for k in range(2,t-1,2): perm.extend([k,k-1]) # append remaining high endpoints? if t%2==1: # after k up to t-3,t-4, append t-1?, t? # for t=9, loop k=2,4,6,8? range(2,8,2)=2,4,6 -> [2,1,4,3,6,5], append8,9 perm.extend([t-1,t]) else: # for t=8, start7, loop k=2,4,6? append [2,1,4,3,6,5], append8 perm.append(t) return perm def coords_from_perm(perm, extra_even=True): cols=[0] rows=[0] for i in range(len(perm)-1): gap=(perm[i]+perm[i+1])//2 # for even t maybe add extra gap to first? Need check cols.append(cols[-1]+gap) rows.append(1-rows[-1]) # alternate if len(perm)%2==0 and extra_even: # add one to all after some position maybe after label1? easiest add to last coordinate? increases gaps for pairs across cut. pass return {x:(rows[i],cols[i]) for i,x in enumerate(perm)} def check_deficits(coords): xs=list(coords) ok=True; bad=[] for i,x in enumerate(xs): for y in xs[i+1:]: r1,c1=coords[x]; r2,c2=coords[y] d=abs(c1-c2)+(r1!=r2) req=(x+y)//2+1 if d<req: ok=False; bad.append((x,y,d,req)) width=max(c for r,c in coords.values())-min(c for r,c in coords.values())+1 return ok,width,bad[:10] for t in range(3,12): perm=construction_perm(t) coords=coords_from_perm(perm) print(t,perm,check_deficits(coords))
pythondef rec_coords(t): # Returns coords for deficits 1..t width W(t) if t==1: return {1:(0,0)} if t==2: return {2:(0,0),1:(1,1)} if t==3: return {3:(0,0),2:(1,2),1:(0,3)} if t==4: return {4:(0,0),3:(1,3),2:(0,5),1:(1,6)} old=rec_coords(t-2) # put t at left col 0 row0; shift old by a? put t-1 at right W(t)-1 row? # try a=t-2 or t-1; rows maybe flip depending. width_old=max(c for r,c in old.values())+1 for a in range(0,2*t): for row_t in [0,1]: for row_r in [0,1]: # maybe flip old rows or not for flip in [0,1]: coords={t:(row_t,0), t-1:(row_r,W(t)-1)} for x,(r,c) in old.items(): coords[x]=(r^flip,c+a) ok,width,bad=check_deficits(coords) if ok and width==W(t): return coords raise Exception("no") for t in range(1,13): coords=rec_coords(t) print("t",t,"width",check_deficits(coords)[1], "W",W(t), "coords", sorted(coords.items())) # print grid
pythondef walk_positions(t): col=0; row=0 coords={0:(row,col)} for i in range(1,t+1): # change row every time row=1-row step=i-1 if i==1: sign=1 else: block=(i-2)//2 sign=1 if block%2==0 else -1 col += sign*step coords[i]=(row,col) minc=min(c for r,c in coords.values()) coords={i:(r,c-minc) for i,(r,c) in coords.items()} width=max(c for r,c in coords.values())+1 return coords,width def check_deficits_subset(coords, include0=False): xs=[x for x in coords if include0 or x>0] bad=[] for idx,x in enumerate(xs): for y in xs[idx+1:]: r1,c1=coords[x]; r2,c2=coords[y] d=abs(c1-c2)+(r1!=r2) # condition for deficits x,y, both low if positive: req=floor((x+y)/2)+1 req=(x+y)//2 +1 if d<req: bad.append((x,y,d,req)) return bad for t in range(1,13): coords,width=walk_positions(t) low_coords={i:coords[i] for i in range(1,t+1)} minc=min(c for r,c in low_coords.values()) low_coords={i:(r,c-minc) for i,(r,c) in low_coords.items()} low_width=max(c for r,c in low_coords.values())+1 print("t",t,"allwidth",width,"lowwidth",low_width,"W",W(t),"bad",check_deficits_subset(low_coords)[:3],"coords",coords)
pythondef feasible_deficits_with0(t,n,find=False): vals=list(range(t, -1, -1)) # include 0 verts=[(r,c) for c in range(n) for r in range(2)] N=2*n dist=[[abs(c1-c2)+(r1!=r2) for (r2,c2) in verts] for (r1,c1) in verts] def req(x,y): return (x+y)//2 + 1 def rec(idx, usedmask, ass): if idx==len(vals): return ass x=vals[idx] candidates=[] for v in range(N): if usedmask>>v &1: continue ok=True for y,vy in ass.items(): if dist[v][vy] < req(x,y): ok=False;break if ok: candidates.append(v) if idx==0: candidates=[v for v in candidates if verts[v][0]==0 and verts[v][1]<= (n-1)//2] candidates.sort(key=lambda v: abs(verts[v][1]-(n-1)/2)) for v in candidates: res=rec(idx+1,usedmask|1<<v,{**ass,x:v}) if res is not None: return res return None res=rec(0,0,{}) if find and res is not None: return True,{x:verts[v] for x,v in res.items()} return res is not None def W0(t): for n in range(1,100): if feasible_deficits_with0(t,n): return n for t in range(1,9): print(t,W0(t), "W", W(t))
pythonfor t in range(1,9): n=W0(t) ok,assign=feasible_deficits_with0(t,n,find=True) print("t",t,"n",n,assign) grid=[["." for _ in range(n)] for _ in range(2)] for x,(r,c) in assign.items(): grid[r][c]=str(x) for row in grid: print(" ".join(f"{v:>2}" for v in row)) print()
pythonimport itertools, math def path_weight(perm): return sum((perm[i]+perm[i+1])//2 for i in range(len(perm)-1)) def equality_paths(s, limit=20): target=math.ceil(s*s/2 - s +1) paths=[] for perm in itertools.permutations(range(1,s+1)): if path_weight(perm)==target: paths.append(perm) if len(paths)>=limit: break return target,paths for s in [4,6]: target,paths=equality_paths(s,1000) print("s",s,"target",target,"num_sample",len(paths)) for p in paths[:10]: # construct cols gaps minimal, rows alternating cols=[0] for i in range(s-1): cols.append(cols[-1]+(p[i]+p[i+1])//2) rows=[i%2 for i in range(s)] coords={p[i]:(rows[i],cols[i]) for i in range(s)} bad=check_deficits(coords)[2] print(p,bad[:3]) print()
pythondef coords_from_perm_with_extra(perm, extra_after_label=None): cols=[0]; rows=[0] for i in range(len(perm)-1): gap=(perm[i]+perm[i+1])//2 if extra_after_label is not None and perm[i]==extra_after_label: gap+=1 cols.append(cols[-1]+gap) rows.append(1-rows[-1]) return {x:(rows[i],cols[i]) for i,x in enumerate(perm)} def even_perm(t): return construction_perm(t) for t in [4,6,8,10]: perm=even_perm(t) coords=coords_from_perm_with_extra(perm,extra_after_label=1) print(t, perm, check_deficits(coords)[:2], check_deficits(coords)[2][:5])
pythondef coords_from_perm_alt(perm): cols=[0]; rows=[0] for i in range(len(perm)-1): cols.append(cols[-1]+(perm[i]+perm[i+1])//2) rows.append(1-rows[-1]) return {x:(rows[i],cols[i]) for i,x in enumerate(perm)} for perm in [(5,2,3,1,4),(7,4,5,2,3,1,6),(9,6,7,4,5,2,3,1,8)]: coords=coords_from_perm_alt(list(perm)) print(perm, path_weight(perm), check_deficits(coords)[:2], check_deficits(coords)[2][:5])
pythondef coords_even(t): perm=even_perm(t) return coords_from_perm_with_extra(perm,extra_after_label=1) def perm_odd(t): # t odd >=3 perm=[t] # pairs (t-3,t-2), descending by 2 down to (2,3) for a in range(t-3,1,-2): perm.extend([a,a+1]) perm.extend([1,t-1]) return perm def coords_odd(t): return coords_from_perm_alt(perm_odd(t)) def possible_zero(coords,t): width=check_deficits(coords)[1] positions=[] for c in range(width): for r in [0,1]: if (r,c) in coords.values(): continue ok=True for i,(ri,ci) in coords.items(): d=abs(c-ci)+(r!=ri) req=i//2 +1 # floor(i/2)+1 if d<req: ok=False;break if ok: positions.append((r,c)) return positions for t in range(3,11): coords=coords_odd(t) if t%2 else coords_even(t) print("t",t,"width",check_deficits(coords)[1],"zero options",possible_zero(coords,t)[:10]) # print coords print(sorted(coords.items(), key=lambda kv: kv[1][1]))
pythondef req_for_def(x,y): # x,y are deficits: label n-x and n-y. For y negative means high label. # condition: dist + ceil((2n - x - y)/2) >= n+1 # ceil(n - (x+y)/2)= n - floor((x+y)/2) # req = floor((x+y)/2)+1. If <=1, distinct vertices automatically at dist>=1. return max(1, (x+y)//2 + 1) def feasible_special(t,n,find=False): vals=list(range(t, -(t-2)-1, -1)) # t,t-1,...,-(t-2) # order maybe positives first descending then 0 then negatives descending? # To search, use sorted by absolute/positive? Use vals as t..negative verts=[(r,c) for c in range(n) for r in range(2)] N=2*n dist=[[abs(c1-c2)+(r1!=r2) for (r2,c2) in verts] for (r1,c1) in verts] def rec(idx, usedmask, ass): if idx==len(vals): return ass x=vals[idx] candidates=[] for v in range(N): if usedmask>>v & 1: continue ok=True for y,vy in ass.items(): if dist[v][vy] < req_for_def(x,y): ok=False;break if ok:candidates.append(v) if idx==0: candidates=[v for v in candidates if verts[v][0]==0 and verts[v][1]<= (n-1)//2] candidates.sort(key=lambda v: abs(verts[v][1]-(n-1)/2)) for v in candidates: res=rec(idx+1, usedmask|1<<v, {**ass,x:v}) if res is not None:return res return None res=rec(0,0,{}) if find and res is not None: return True,{x:verts[v] for x,v in res.items()} return res is not None for t in range(1,9): n= max(W0(t),2*t-1) # actually width W? print("t",t,"W0",W0(t),"2t-1",2*t-1, "feas at W0", feasible_special(t,W0(t))) if feasible_special(t,W0(t)): ok,assign=feasible_special(t,W0(t),find=True) print(assign)
pythondef special_extend_from_coords(coords,t): # coords positives, place 0 and negatives greedily maybe using known zero then search # We'll search with fixed positives for remaining 0,-1,... width=check_deficits(coords)[1] verts=[(r,c) for c in range(width) for r in range(2)] N=2*width used=set(coords.values()) vals=[0]+[-j for j in range(1,t-1)] ass={**coords} # sort maybe 0, -1... def rec(idx,ass,used): if idx==len(vals): return ass x=vals[idx] cands=[] for v in verts: if v in used: continue ok=True for y,vy in ass.items(): d=abs(v[1]-vy[1])+(v[0]!=vy[0]) if d<req_for_def(x,y): ok=False;break if ok: cands.append(v) # prefer near label1/zero cands.sort(key=lambda rc: (abs(rc[1]-width/2), rc[0])) for v in cands: res=rec(idx+1,{**ass,x:v}, used|{v}) if res: return res return None return rec(0,ass,used) for t in range(3,11): coords=coords_odd(t) if t%2 else coords_even(t) ass=special_extend_from_coords(coords,t) print("t",t, "width",check_deficits(coords)[1]) print(sorted(ass.items(), key=lambda kv: kv[1][1])) print()
pythonfor n in [26,27,30,50]: t=math.floor(1+math.sqrt(2*n-4)) M=3*n-t-1 print(n,t,M) # check n26 M70 with solver maybe ok,nodes,ass=feasible_ladder(26,70,time_limit_nodes=2000000) print("n26 M70",ok,nodes)
已按图 4-3 所示的 写成 PDF,包含精确公式、上下界证明和一个 的标号示例。
PDF 下载: 无线电平均标号数证明
从数学角度重新给定这个标号函数,不要是什么亏量,因为从未听过这个定义,就是确切的数值,结果以PDF格式输出
pythonfrom itertools import combinations, permutations def ladder_dist(n): verts=[(r,i) for i in range(2) for i in range(1,n+1)] D={} for a,u in enumerate(verts): for b,v in enumerate(verts): D[a,b]=abs(u[1]-v[1])+(u[0]!=v[0]) return verts,D def feasible(n,m, verbose=False): V,D=ladder_dist(n) N=len(V) # choose N labels from 1..m? Better assign labels maybe all but holes. # We can choose vertices for each used label; skip labels allowed. Backtrack label 1..m deciding use or skip. # Need use N labels. Low labels constrained. Use symmetry graph autom? skip. min_dist_req={} labels=range(1,m+1) for a in labels: for b in labels: if a<b: # need d >= ceil((2n+1 - (a+b))/2) if positive req=max(0, (2*n+1 - (a+b) +1)//2) # ceil # actually if req<=0, no constraint min_dist_req[(a,b)]=req # domain for labels: all vertices; if label pairs require req>n impossible? But pairs may not both used. # Backtrack used labels increasing; try always use smaller labels? skipping maybe needed. # If using label l, skip decision. Lower bound: if remaining labels enough. assigned={} # label->vertex index used_vertices=set() # Use labels in increasing order; use MRV? use/skip. # For canonical, use label 1? likely yes for minim max, but maybe maybe yes because replacing min used label with 1 decreases constraints? actually lower label makes constraints harder, so not necessarily use 1. But labels are positive, skipping small labels can help but increases span maybe. For fixed m, feasible subset of N labels; not necessarily includes 1. # Need choose subset. We'll search labels descending? large less constrained, but low constrained. # Use recursion on labels ascending with skip. # Symmetry: fix label 1 to a representative? Maybe if label 1 used. But can skip. vert_order=list(range(N)) # Sort vertices by maybe position; no need. def can_assign(label, v): for lab,u in assigned.items(): req=min_dist_req[(lab,label) if lab<label else (label,lab)] if D[u,v] < req: return False return True def rec(label, used_count): if label>m: return used_count==N rem=m-label+1 if used_count+rem<N: return False # If used_count==N: can ignore rest? But max span m requires label m? Actually rmn(f) <= m, not necessarily uses m. Feasible for <=m. Then true. if used_count==N: return True # try skip? For small labels perhaps skipping beneficial. But to minimize max, not necessarily use all smallest labels. Try use/skip maybe. # But if rem == N-used_count, must use all. # Try use label maybe if likely. # choose candidate vertices that satisfy constraints if rem == N-used_count: do_skip=False else: do_skip=True # maybe skip first for low constrained? For feasibility skip may succeed quicker if do_skip and rec(label+1, used_count): return True # use # candidates sorted by pruning for v in vert_order: if v not in used_vertices and can_assign(label,v): assigned[label]=v; used_vertices.add(v) if rec(label+1, used_count+1): return True used_vertices.remove(v); del assigned[label] return False res=rec(1,0) if verbose and res: print("assign", assigned) return res for n in range(1,8): lo=2*n m=lo while not feasible(n,m): m+=1 print(n,m)
pythonfrom functools import lru_cache def feasible_subset(n, labels, ret=False): V,D=ladder_dist(n); N=len(V) labels=tuple(sorted(labels)) req={} for i,a in enumerate(labels): for j,b in enumerate(labels): if i<j: req[(a,b)]=max(0,(2*n+1-(a+b)+1)//2) # constraint degree deg={a:sum(req[tuple(sorted((a,b)))]>0 for b in labels if b!=a) for a in labels} assigned={} used=set() # choose unassigned label with min remaining? Build candidates each step. def ok(a,v): for b,u in assigned.items(): r=req[tuple(sorted((a,b)))] if D[u,v]<r: return False return True def rec(): if len(assigned)==N: return True # choose label among unassigned with smallest candidates best=None; cands=None for a in labels: if a not in assigned: ca=[v for v in range(N) if v not in used and ok(a,v)] if not ca: return False # sort by degree descending? if best is None or len(ca)<len(cands) or (len(ca)==len(cands) and deg[a]>deg[best]): best=a; cands=ca # symmetry break: first label maybe restrict to one orbit? for v in cands: assigned[best]=v; used.add(v) if rec(): return True used.remove(v); del assigned[best] return False res=rec() if ret and res: return assigned.copy() return res for n in [5,7]: m=3*n-2-int((2*n-4)**0.5) print("n oldM",n,m) for skips in combinations(range(1,m+1), m-2*n): labels=[x for x in range(1,m+1) if x not in skips] if feasible_subset(n, labels): print("feasible",skips) break else: print("none") print("n7 labels 3..16", feasible_subset(7, range(3,17), ret=True))
pythonfor n in range(8,11): for m in range(2*n, 2*n+10): ok=feasible(n,m) if ok: print("n",n,"m",m,"formula",2*n+(n-1)//2) break
pythondef active_feasible(t, ncols, ret=False): V,D=ladder_dist(ncols) deficits=list(range(t,1-t,-1)) # t,t-1,...,2-t # req between deficits req={} for a in deficits: for b in deficits: if a<b: req[(a,b)]=max(1,1+(a+b)//2) # floor in py ok for negative; but if <=1 automatic distinct distance>=1 assigned={} used=set() deg={a:sum(req[tuple(sorted((a,b)))]>1 for b in deficits if b!=a) for a in deficits} # order with MRV def ok(a,v): for b,u in assigned.items(): if D[u,v] < req[tuple(sorted((a,b)))]: return False return True def rec(): if len(assigned)==len(deficits): return True best=None;cands=None for a in deficits: if a not in assigned: ca=[v for v in range(len(V)) if v not in used and ok(a,v)] if not ca: return False if best is None or len(ca)<len(cands) or (len(ca)==len(cands) and deg[a]>deg[best]): best=a;cands=ca for v in cands: assigned[best]=v; used.add(v) if rec(): return True used.remove(v); del assigned[best] return False res=rec() if ret and res: return assigned.copy(), V return res for t in range(1,9): c=1 while not active_feasible(t,c): c+=1 print("t",t,"c",c, "old", (t*t//2 - t + 3 if t>=3 else (1 if t==1 else 3))) ass,V=active_feasible(t,c,True) # print sorted by column arr=[["." for _ in range(c)] for _ in range(2)] for x,v in ass.items(): r,col=V[v]; arr[r][col-1]=str(x) print(arr)
pythondef check_active_assignment(t,ncols, assign): V,D=ladder_dist(ncols) for x,vx in assign.items(): for y,vy in assign.items(): if x<y: req=max(1,1+((x+y)//2)) if D[vx,vy] < req: print("fail",x,y,D[vx,vy],req) return False return True V,D=ladder_dist(3) print(V) assign={2:0,1:4,0:2} # top col1, bottom col2 index? verts row0 col1..3, row1 col1..3 => bottom col2 index 4 print(check_active_assignment(2,3,assign)) print(active_feasible(2,3,True))
pythonimport inspect print(inspect.getsource(ladder_dist))
pythondef ladder_dist(n): verts=[(r,i) for r in range(2) for i in range(1,n+1)] D={} for a,u in enumerate(verts): for b,v in enumerate(verts): D[a,b]=abs(u[1]-v[1])+(u[0]!=v[0]) return verts,D # redefine feasible def feasible(n,m, verbose=False): V,D=ladder_dist(n) N=len(V) labels=range(1,m+1) min_dist_req={} for a in labels: for b in labels: if a<b: req=max(0, (2*n+1 - (a+b) +1)//2) min_dist_req[(a,b)]=req assigned={} used_vertices=set() vert_order=list(range(N)) def can_assign(label, v): for lab,u in assigned.items(): req=min_dist_req[(lab,label) if lab<label else (label,lab)] if D[u,v] < req: return False return True def rec(label, used_count): if used_count==N: if verbose: print(assigned) return True if label>m: return False rem=m-label+1 if used_count+rem<N: return False # skip first maybe if rem > N-used_count and rec(label+1, used_count): return True for v in vert_order: if v not in used_vertices and can_assign(label,v): assigned[label]=v; used_vertices.add(v) if rec(label+1, used_count+1): return True used_vertices.remove(v); del assigned[label] return False return rec(1,0) for n in range(1,11): m=2*n while not feasible(n,m): m+=1 print(n,m, "old", 2 if n==1 else 3*n-2-int((2*n-4)**0.5))
pythondef pos_order(t): if t==1: return [1] if t%2==0: r=t//2 order=[2*r-1,2,1] for k in range(2,r): order += [2*k,2*k-1] # wait for t=6 r=3 should [5,2,1,4,3,6]? yes order += [2*r] if 2*r not in order else [] return order else: r=(t-1)//2 order=[2*r+1] # from 2r-2,2r-1 down to 2,3 then 1,2r for a in range(2*r-2,1,-2): order += [a,a+1] order += [1,2*r] return order for t in range(1,8): print(t,pos_order(t),len(pos_order(t))) def positive_positions(t): order=pos_order(t) cols=[1] rows=[0] for i in range(len(order)-1): a,b=order[i],order[i+1] cols.append(cols[-1]+(a+b)//2) # floor rows.append(1-rows[-1]) return {a:(r,c) for a,r,c in zip(order,rows,cols)}, order, cols[-1] def check_positions(pos,t): for a,(ra,ca) in pos.items(): for b,(rb,cb) in pos.items(): if a<b: d=abs(ca-cb)+(ra!=rb) req=max(1,1+(a+b)//2) if d<req: return False,(a,b,d,req) return True,None for t in range(2,7): pos,order,L=positive_positions(t) print("t",t,"L",L,"ell", (t*t//2 - t +3 if t>=3 else 3), "ok",check_positions(pos,t)) print(pos)
pythondef positive_positions_old(t): if t==1: return {1:(0,1)}, [1], 1 if t==2: # maybe place 2 and 1 at distance 2 in 3 cols, e.g. top1 bottom2; L=3 return {2:(0,1), 1:(1,2)}, [2,1], 3 if t%2==0: r=t//2 order=[2*r-1,2,1] for k in range(2,r): order += [2*k,2*k-1] order += [2*r] # remove duplicates if any? for r=2 no loop [3,2,1,4] else: r=(t-1)//2 order=[2*r+1] for a in range(2*r-2,1,-2): order += [a,a+1] order += [1,2*r] cols=[1]; rows=[0] for i in range(len(order)-1): a,b=order[i],order[i+1] gap=(a+b)//2 if t%2==0
pythondef simple_complete(t): pos, order,L=positive_positions_old(t) comp=pos.copy() for s in range(0,t-1): # q=-s, target positive s+1 p=s+1; q=-s if q in comp: continue r,c=pos[p] comp[q]=(1-r,c) return comp,L for t in range(1,8): comp,L=simple_complete(t) print(t,L, check_positions(comp,t)) if not check_positions(comp,t)[0]: print(comp)
pythondef safe_positions_for_q(t,q, fixed=None): pos,order,L=positive_positions_old(t) if fixed: pos={**pos, **fixed} occupied=set(pos.values()) safe=[] for r in [0,1]: for c in range(1,L+1): if (r,c) in occupied: continue ok=True for p,(rp,cp) in pos.items(): req=max(1,1+((q+p)//2)) d=abs(c-cp)+(r!=rp) if d<req: ok=False; break if ok: safe.append((r,c)) return safe for t in [5,6,7]: print("t",t,"positive",positive_positions_old(t)[0]) fixed={} for q in range(0,1-t,-1): safe=safe_positions_for_q(t,q,fixed) print("q",q,"safe first",safe[:20],"count",len(safe)) # choose CP perhaps lexicographic if safe: fixed[q]=safe[0] print("greedy",fixed, check_positions({**positive_positions_old(t)[0],**fixed},t))
pythonfor t in [8,9,10]: pos,order,L=positive_positions_old(t) fixed={} ok=True for q in range(0,1-t,-1): safe=safe_positions_for_q(t,q,fixed) if not safe: ok=False; break fixed[q]=safe[0] print("t",t,"L",L,"ok",ok, "check", check_positions({**pos,**fixed},t) if ok else None) print("order",order) print("pos",pos) print("fixed",fixed)
pythondef explicit_complete(t): pos,order,L=positive_positions_old(t) comp=pos.copy() if t==1: return comp,L if t==2: # positive positions old: q2 top c1, q1 bottom c2, L=3 comp[0]=(0,3) return comp,L if t%2==1: r=(t-1)//2 # q0: same row as q1, column c(q1)-1 r1,c1=pos[1] comp[0]=(r1,c1-1) for s in range(1,t-1): if s%2==1: k=(s+1)//2 c=r+k+1 else: k=s//2 c=r+2-k comp[-s]=(0,c) else: r=t//2 comp[0]=(0,r+3) for s in range(1,t-1): if s==1: c=r+1 elif s%2==0: k=s//2 c=r+1-k else: k=(s-1)//2 # s=2k+1 c=r+k+3 comp[-s]=(0,c) return comp,L for t in range(1,15): comp,L=explicit_complete(t) ok=check_positions(comp,t) used=len(set(comp.values()))==len(comp) within=all(1<=c<=L and r in (0,1) for r,c in comp.values()) print(t,L,ok,used,within) if not ok[0] or not used or not within: print(comp) break
pythonfor t in [11,12,13,14,15]: pos,order,L=positive_positions_old(t) fixed={} for q in range(0,1-t,-1): safe=safe_positions_for_q(t,q,fixed) if not safe: print("fail q",q) break fixed[q]=safe[0] print("t",t,"L",L,"check",check_positions({**pos,**fixed},t)) print("fixed",fixed)
pythondef simple_neg_right(t,row=1): pos,order,L=positive_positions_old(t) comp=pos.copy() for s in range(0,t-1): comp[-s]=(row,L-s) return comp,L for row in [0,1]: okall=True for t in range(3,20): comp,L=simple_neg_right(t,row) if len(set(comp.values()))<len(comp): okall=False; print("row",row,"bad coll",t); break ok=check_positions(comp,t) if not ok[0]: okall=False; print("row",row,"bad",t,ok[1]); break print(row,okall)
pythonfor t in range(3,31,2): comp,L=explicit_complete(t) ok=check_positions(comp,t) used=len(set(comp.values()))==len(comp) if not ok[0] or not used: print("odd fail",t, ok, used) break else: print("odd all ok")
pythonfrom itertools import permutations for s in range(1,8): mn=999; arg=None for p in permutations(range(1,s+1)): val=sum((p[i]+p[i+1])//2 for i in range(s-1)) if val<mn: mn=val;arg=p print(s,mn,arg,"ell", (1 if s==1 else 3 if s==2 else s*s//2-s+2)) # n-1? ell-1
pythondef construct_labels(n): if n==1: return {(0,1):1,(1,1):2} import math t=1+int(math.isqrt(2*n-4)) # floor sqrt M=3*n-t-1 comp,L=explicit_complete(t) # comp maps q to (row,col) within first L labels={} for q,(r,c) in comp.items(): labels[(r,c)]=n-q next_label=n+t-1 for c in range(1,n+1): for r in [0,1]: if (r,c) not in labels: labels[(r,c)]=next_label next_label+=1 assert next_label==M+1 return labels, t,M,L,comp labels,t,M,L,comp=construct_labels(10) print(t,M,L,comp) for r in [0,1]: print([labels[(r,c)] for c in range(1,11)]) # verify def verify_labeling(n, labels): V,D=ladder_dist(n) inv={v:labels[v] for v in labels} for i,u in enumerate(V): for j,v in enumerate(V): if i<j: if D[i,j]+((inv[u]+inv[v]+1)//2)<n+1: return False,u,v,D[i,j],inv[u],inv[v] return True print(verify_labeling(10,labels))
pythondef explicit_complete_even_with_B(t): pos,order,L=positive_positions_old(t) r=t//2 comp=pos.copy() if t==2: comp[0]=(0,3); return comp,L comp[0]=(0,r+3) # top occupied occupied_top={c for q,(row,c) in comp.items() if row==0} B=[] # generate enough terms seq=[r+1,r] for k in range(1,10*t): seq.extend([r+k+3, r-k]) seen=set() for a in seq: if a<1 or a>L or a in seen: continue seen.add(a) if a in occupied_top: continue B.append(a) if len(B)>=t-2: break for s,c in enumerate(B, start=1): comp[-s]=(0,c) return comp,L for t in range(2,60,2): comp,L=explicit_complete_even_with_B(t) ok=check_positions(comp,t) used=len(set(comp.values()))==len(comp) if not ok[0] or not used or len(comp)!=2*t-1: print("fail",t,L,ok,used,len(comp)) #print(comp) break else: print("even all ok")
pythont=14 comp,L=explicit_complete_even_with_B(t) print({q:comp[q] for q in sorted(comp) if q<=0 or q in [13,3]}) print(check_positions(comp,t)) # find q -11 position print("pos -11",comp[-11], "pos13", comp[13])
pythonfor t in [14]: pos,order,L=positive_positions_old(t) for q in sorted([q for q in pos]): print(q,pos[q])
已重新整理为 PDF,改为直接给出数学标号函数,并保留确切数值、表达式、下界与上界证明。