পাইথন 2 এবং পিএলপি - 2,644,688 স্কোয়ার (অনুকূলভাবে ছোট করা); 10,753,553 স্কোয়ার (অনুকূল সর্বাধিক)
সর্বনিম্ন 1152 বাইটে গল্ফড
from pulp import*
x=0
f=open("c","r")
g=open("s","w")
for k,m in enumerate(f):
if k%2:
b=map(int,m.split())
p=LpProblem("Nn",LpMinimize)
q=map(str,range(18))
ir=q[1:18]
e=LpVariable.dicts("c",(q,q),0,1,LpInteger)
rs=LpVariable.dicts("rs",(ir,ir),0,1,LpInteger)
cs=LpVariable.dicts("cs",(ir,ir),0,1,LpInteger)
p+=sum(e[r][c] for r in q for c in q),""
for i in q:p+=e["0"][i]==0,"";p+=e[i]["0"]==0,"";p+=e["17"][i]==0,"";p+=e[i]["17"]==0,""
for o in range(289):i=o/17+1;j=o%17+1;si=str(i);sj=str(j);l=e[si][str(j-1)];ls=rs[si][sj];p+=e[si][sj]<=l+ls,"";p+=e[si][sj]>=l-ls,"";p+=e[si][sj]>=ls-l,"";p+=e[si][sj]<=2-ls-l,"";l=e[str(i-1)][sj];ls=cs[si][sj];p+=e[si][sj]<=l+ls,"";p+=e[si][sj]>=l-ls,"";p+=e[si][sj]>=ls-l,"";p+=e[si][sj]<=2-ls-l,""
for r,z in enumerate(a):p+=lpSum([rs[str(r+1)][c] for c in ir])==2*z,""
for c,z in enumerate(b):p+=lpSum([cs[r][str(c+1)] for r in ir])==2*z,""
p.solve()
for r in ir:
for c in ir:g.write(str(int(e[r][c].value()))+" ")
g.write('\n')
g.write('%d:%d\n\n'%(-~k/2,value(p.objective)))
x+=value(p.objective)
else:a=map(int,m.split())
print x
(এনবি: ভারী চাপযুক্ত লাইনগুলি ফাঁকা নয়, ট্যাব দিয়ে শুরু হয়))
উদাহরণ আউটপুট: https://drive.google.com/file/d/0B-0NVE9E8UJiX3IyQkJZVk82Vkk/view?usp=sharing
দেখা যাচ্ছে যে এর মতো সমস্যাগুলি সহজেই ইন্টিজার লিনিয়ার প্রোগ্রামগুলিতে রূপান্তরিত হয় এবং আমার নিজের প্রকল্পের জন্য কীভাবে পিএলপি a বিভিন্ন এলপি সলভারগুলির জন্য একটি পাইথন ইন্টারফেস learn কীভাবে ব্যবহার করতে হয় তা শিখতে আমার একটি প্রাথমিক সমস্যা প্রয়োজন। এটিও প্রমাণিত হয়েছে যে পিএলপি ব্যবহার করা অত্যন্ত সহজ এবং অবহেলিত এলপি নির্মাতা প্রথমবার চেষ্টা করার সময় পুরোপুরি কাজ করেছিলেন।
আমার জন্য এটি সমাধানের কঠোর পরিশ্রম করার জন্য একটি শাখা-এবং-বাউন্ডে আইপি সলভার নিয়োগের বিষয়ে দুটি সুন্দর জিনিস (কোনও শাখা এবং আবদ্ধ সলভার প্রয়োগ না করেই) হ'ল
- উদ্দেশ্য-নির্মিত solvers সত্যিই দ্রুত। এই প্রোগ্রামটি আমার অপেক্ষাকৃত কম-শেষ হোম পিসিতে প্রায় 17 ঘন্টাগুলিতে সমস্ত 50000 টি সমস্যা সমাধান করে। প্রতিটি উদাহরণ সমাধান করতে 1-1.5 সেকেন্ড থেকে সময় নিয়েছে।
- তারা গ্যারান্টিযুক্ত অনুকূল সমাধান উত্পাদন করে (বা আপনাকে বলবে যে তারা এটি করতে ব্যর্থ হয়েছে)। সুতরাং, আমি আত্মবিশ্বাসের সাথে বলতে পারি যে কেউ স্কোরগুলিতে আমার স্কোরকে পরাজিত করবে না (যদিও কেউ এটি বেঁধে আমাকে গল্ফিংয়ের অংশে পরাজিত করতে পারে)।
এই প্রোগ্রামটি কীভাবে ব্যবহার করবেন
প্রথমত, আপনাকে পিএলপি ইনস্টল করতে হবে। pip install pulp
আপনার যদি পাইপ ইনস্টল থাকে তবে কৌশলটি করা উচিত।
তারপরে, আপনাকে "সি" নামক একটি ফাইলে নিম্নলিখিতটি লিখতে হবে: https://drive.google.com/file/d/0B-0NVE9E8UJiNFdmYlk1aV9aYzQ/view?usp=sharing
তারপরে, একই ডিরেক্টরি থেকে যেকোন দেরিতে পাইথন 2 বিল্ডে এই প্রোগ্রামটি চালান। এক দিনেরও কম সময়ে, আপনার কাছে "এস" নামক একটি ফাইল থাকবে যার মধ্যে 50,000 সলভ ননোগ্রাম গ্রিড রয়েছে (পঠনযোগ্য বিন্যাসে) রয়েছে যার প্রতিটি নীচে তালিকাভুক্ত মোট পূর্ণ সংখ্যা সহ।
আপনি যদি এর পরিবর্তে ভরা স্কোয়ারের সংখ্যাটি সর্বাধিক করতে চান তবে LpMinimize
8 লাইনটি LpMaximize
পরিবর্তে পরিবর্তিত করুন। আপনি এর মতো আউটপুটটি পাবেন: https://drive.google.com/file/d/0B-0NVE9E8UJiYjJ2bzlvZ0RXcUU/view?usp=sharing
ছক পূরণ করা
এই প্রোগ্রামটি একটি পরিবর্তিত ইনপুট ফর্ম্যাট ব্যবহার করে, যেহেতু জো জেড বলেছেন যে ওপিতে কোনও মন্তব্য করতে চাইলে আমাদের ইনপুট ফর্ম্যাটটি পুনরায় এনকোড করার অনুমতি দেওয়া হবে। এটি দেখতে কেমন তা দেখতে উপরের লিঙ্কটিতে ক্লিক করুন। এটি 10000 লাইন নিয়ে গঠিত, যার প্রত্যেকটিতে 16 সংখ্যা রয়েছে। এমনকি সংখ্যায়িত রেখাগুলি একটি নির্দিষ্ট উদাহরণের সারিগুলির দৈর্ঘ্য, যখন বিজোড় সংখ্যাযুক্ত রেখাগুলি তাদের উপরের রেখার মতো একই উদাহরণের কলামগুলির দৈর্ঘ্য। এই ফাইলটি নিম্নলিখিত প্রোগ্রাম দ্বারা উত্পাদিত হয়েছিল:
from bitqueue import *
with open("nonograms_b64.txt","r") as f:
with open("nonogram_clues.txt","w") as g:
for line in f:
q = BitQueue(line.decode('base64'))
nonogram = []
for i in range(256):
if not i%16: row = []
row.append(q.nextBit())
if not -~i%16: nonogram.append(row)
s=""
for row in nonogram:
blocks=0 #magnitude counter
for i in range(16):
if row[i]==1 and (i==0 or row[i-1]==0): blocks+=1
s+=str(blocks)+" "
print >>g, s
nonogram = map(list, zip(*nonogram)) #transpose the array to make columns rows
s=""
for row in nonogram:
blocks=0
for i in range(16):
if row[i]==1 and (i==0 or row[i-1]==0): blocks+=1
s+=str(blocks)+" "
print >>g, s
(এই পুনরায় এনকোডিং প্রোগ্রামটিও আমাকে উপরে উল্লিখিত একই প্রকল্পের জন্য আমার কাস্টম বিটকিউ ক্লাস পরীক্ষা করার জন্য একটি অতিরিক্ত সুযোগ দিয়েছে It এটি কেবল একটি সারি যা ডেটা বিট বা বাইটের ক্রম হিসাবে ঠেলা যায় এবং কোন ডেটা থেকে একসাথে কিছুটা বা বাইট পপ করুন be এই পরিস্থিতিতে এটি পুরোপুরি কাজ করেছে))
আমি নির্দিষ্ট কারণের জন্য ইনপুটটিকে পুনরায় এনকোড করেছি যে আইএলপি তৈরি করতে, গ্রিডিউড তৈরি করতে ব্যবহৃত গ্রিডগুলি সম্পর্কে অতিরিক্ত তথ্য পুরোপুরি অকেজো। মাত্রা একমাত্র প্রতিবন্ধকতা এবং তাই চৌম্বকগুলি কেবল আমার অ্যাক্সেসের প্রয়োজন।
অবহেলিত আইএলপি নির্মাতা
from pulp import *
total = 0
with open("nonogram_clues.txt","r") as f:
with open("solutions.txt","w") as g:
for k,line in enumerate(f):
if k%2:
colclues=map(int,line.split())
prob = LpProblem("Nonogram",LpMinimize)
seq = map(str,range(18))
rows = seq
cols = seq
irows = seq[1:18]
icols = seq[1:18]
cells = LpVariable.dicts("cell",(rows,cols),0,1,LpInteger)
rowseps = LpVariable.dicts("rowsep",(irows,icols),0,1,LpInteger)
colseps = LpVariable.dicts("colsep",(irows,icols),0,1,LpInteger)
prob += sum(cells[r][c] for r in rows for c in cols),""
for i in rows:
prob += cells["0"][i] == 0,""
prob += cells[i]["0"] == 0,""
prob += cells["17"][i] == 0,""
prob += cells[i]["17"] == 0,""
for i in range(1,18):
for j in range(1,18):
si = str(i); sj = str(j)
l = cells[si][str(j-1)]; ls = rowseps[si][sj]
prob += cells[si][sj] <= l + ls,""
prob += cells[si][sj] >= l - ls,""
prob += cells[si][sj] >= ls - l,""
prob += cells[si][sj] <= 2 - ls - l,""
l = cells[str(i-1)][sj]; ls = colseps[si][sj]
prob += cells[si][sj] <= l + ls,""
prob += cells[si][sj] >= l - ls,""
prob += cells[si][sj] >= ls - l,""
prob += cells[si][sj] <= 2 - ls - l,""
for r,clue in enumerate(rowclues):
prob += lpSum([rowseps[str(r+1)][c] for c in icols]) == 2 * clue,""
for c,clue in enumerate(colclues):
prob += lpSum([colseps[r][str(c+1)] for r in irows]) == 2 * clue,""
prob.solve()
print "Status for problem %d: "%(-~k/2),LpStatus[prob.status]
for r in rows[1:18]:
for c in cols[1:18]:
g.write(str(int(cells[r][c].value()))+" ")
g.write('\n')
g.write('Filled squares for %d: %d\n\n'%(-~k/2,value(prob.objective)))
total += value(prob.objective)
else:
rowclues=map(int,line.split())
print "Total number of filled squares: %d"%total
এটি সেই প্রোগ্রাম যা আসলে উপরে উল্লিখিত "উদাহরণ আউটপুট" তৈরি করেছে actually সুতরাং প্রতিটি গ্রিডের শেষে অতিরিক্ত লম্বা স্ট্রিং, যা আমি এটি গল্ফ করার সময় কেটে ফেলেছিলাম। (গল্ফযুক্ত সংস্করণটি অভিন্ন আউটপুট তৈরি করবে, শব্দগুলি বিয়োগ করবে "Filled squares for "
)
কিভাবে এটা কাজ করে
cells = LpVariable.dicts("cell",(rows,cols),0,1,LpInteger)
rowseps = LpVariable.dicts("rowsep",(irows,icols),0,1,LpInteger)
colseps = LpVariable.dicts("colsep",(irows,icols),0,1,LpInteger)
আমি একটি 18x18 গ্রিড ব্যবহার করি, কেন্দ্রের 16x16 অংশটি আসল ধাঁধা সমাধান হিসাবে। cells
এই গ্রিড হয়? প্রথম লাইন 324 বাইনারি ভেরিয়েবল তৈরি করে: "সেল_0_0", "সেল_0_1", এবং আরও অনেক কিছু। আমি গ্রিডের সমাধান অংশে কোষগুলির মধ্যে এবং তার আশেপাশে "স্পেসস" এর গ্রিডও তৈরি করি। rowseps
289 ভেরিয়েবলগুলিকে নির্দেশ করে যা ফাঁকা স্থানগুলিকে প্রতীকী করে যা কোষগুলিকে অনুভূমিকভাবে পৃথক করে, অন্যদিকে colseps
একইভাবে এমন ভেরিয়েবলগুলিকে নির্দেশ করে যা ফাঁকা স্থানগুলি চিহ্নিত করে যা কোষগুলি উল্লম্বভাবে পৃথক করে। এখানে একটি ইউনিকোড চিত্র রয়েছে:
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|□|0
- - - - - - - - - - - - - - - -
0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0
S এবং □
গুলি দ্বারা ট্র্যাক বাইনারি মান cell
ভেরিয়েবল, |
গুলি বাইনারি মান দ্বারা ট্র্যাক হয় rowsep
ভেরিয়েবল, এবং -
গুলি বাইনারি মান দ্বারা ট্র্যাক হয় colsep
ভেরিয়েবল।
prob += sum(cells[r][c] for r in rows for c in cols),""
এটি উদ্দেশ্যমূলক কাজ। সমস্ত cell
ভেরিয়েবলের যোগফল । যেহেতু এগুলি বাইনারি ভেরিয়েবল, এটি সমাধানে ভরাট স্কোয়ারের ঠিক ঠিক।
for i in rows:
prob += cells["0"][i] == 0,""
prob += cells[i]["0"] == 0,""
prob += cells["17"][i] == 0,""
prob += cells[i]["17"] == 0,""
এটি কেবল গ্রিডের বাইরের প্রান্তের চারপাশের ঘরগুলি শূন্যে সেট করে (এই কারণেই আমি তাদের উপরে জিরো হিসাবে উপস্থাপন করেছি)। কক্ষের কতগুলি "ব্লক" পূরণ করা হয়েছে তা ট্র্যাক করার এটি সর্বাধিক সুস্পষ্ট উপায়, যেহেতু এটি নিশ্চিত করে যে ভরাট থেকে পূর্ণ (কলাম বা সারি পেরিয়ে) প্রতিটি পরিবর্তন পূরণ করা হয় না ভরাট থেকে পূরণ করে (এবং বিপরীতে) ), এমনকি সারির প্রথম বা শেষ ঘরটি পূরণ করা হলেও। এটি প্রথম স্থানে 18x18 গ্রিড ব্যবহারের একমাত্র কারণ। এটি ব্লকগুলি গণনা করার একমাত্র উপায় নয়, তবে আমি মনে করি এটি সবচেয়ে সহজ।
for i in range(1,18):
for j in range(1,18):
si = str(i); sj = str(j)
l = cells[si][str(j-1)]; ls = rowseps[si][sj]
prob += cells[si][sj] <= l + ls,""
prob += cells[si][sj] >= l - ls,""
prob += cells[si][sj] >= ls - l,""
prob += cells[si][sj] <= 2 - ls - l,""
l = cells[str(i-1)][sj]; ls = colseps[si][sj]
prob += cells[si][sj] <= l + ls,""
prob += cells[si][sj] >= l - ls,""
prob += cells[si][sj] >= ls - l,""
prob += cells[si][sj] <= 2 - ls - l,""
এটি আইএলপি-র যুক্তির আসল মাংস। মূলত এটির প্রয়োজন হয় যে প্রতিটি কক্ষটি (প্রথম সারি এবং কলামের ব্যতীত) কোষের লজিকাল জোর এবং তার কাতারে সরাসরি তার বামে এবং বিভাজক হওয়া উচিত। আমি এই বিস্ময়কর উত্তরটি থেকে {0,1} পূর্ণসংখ্যার প্রোগ্রামের মধ্যে একটি জোরকে সীমাবদ্ধ করার মতো প্রতিবন্ধকতা পেয়েছি: /cs//a/12118/44289
আরও কিছুটা ব্যাখ্যা করার জন্য: এই ক্ষুদ্রতর সীমাবদ্ধতা এটিকে এমন করে তোলে যাতে বিভাজকগুলি 1 হতে পারে এবং কেবলমাত্র যদি তারা 0 এবং 1 কোষের মধ্যে থাকে তবে (পরিপূর্ণ থেকে ভরাট বা বিপরীতে পরিবর্তন চিহ্নিত করে)। সুতরাং, একটি সারিতে বা কলামে 1-মানযুক্ত বিভাজক ঠিক তার দ্বিগুণ হবে that সারি বা কলামের ব্লকের সংখ্যা হিসাবে। অন্য কথায়, প্রদত্ত সারি বা কলামে পৃথককারীদের যোগফল সেই সারি / কলামের দৈর্ঘ্যের দ্বিগুণ। অতএব নিম্নলিখিত সীমাবদ্ধতা:
for r,clue in enumerate(rowclues):
prob += lpSum([rowseps[str(r+1)][c] for c in icols]) == 2 * clue,""
for c,clue in enumerate(colclues):
prob += lpSum([colseps[r][str(c+1)] for r in irows]) == 2 * clue,""
এবং thats প্রায় কাছাকাছি এটি. বাকিরা কেবল ডিফল্ট সলভারকে আইএলপি সমাধানের জন্য জিজ্ঞাসা করে, তারপরে ফলাফলটি এটি ফাইলটিতে লেখার সাথে সাথে ফলাফলটি ফর্ম্যাট করে।