একটি ননোগ্রাফিক চৌম্বক অপটিমাইজার তৈরি করুন ™


12

একটি ননোগ্রাম একটি জাপানি ধাঁধা গেম যেখানে লক্ষ্যটি একটি সংক্ষিপ্ত অঞ্চলগুলির তালিকা অনুসারে একটি কালো-সাদা ছবি আঁকতে হবে:

একটি "ল্যাম্বদা" সহ ননগ্রামের একটি উদাহরণ।

একটি সারি বা কলামের অঅনোগ্রাফিক প্রস্থটিকে সেই সারি বা কলামে স্থির কালো অঞ্চলের সংখ্যা হিসাবে সংজ্ঞায়িত করুন । উদাহরণস্বরূপ, উপরের সারিতে 1 টির ননোগ্রাফিক আকার রয়েছে, কারণ সেই সারিতে 2 স্কোয়ারের একটি অঞ্চল রয়েছে। অষ্টম সারিতে 3 টির ননোগ্রাফিক আকার রয়েছে কারণ এটি 2, 2, 1 রয়েছে।

একটি খালি সারি বা কলামে একটি ননোগ্রাফিক মাত্রা 0 রয়েছে।


আপনার টাস্কটি এমন একটি প্রোগ্রাম লিখতে হবে যা কোনও ননোগ্রামের জন্য সলিউশন গ্রিড নিয়ে আসে এবং যতগুলি সম্ভব কম ফিল্ড -ইন স্কোয়ার সহ একটি সলিউশন গ্রিড তৈরি করে যেখানে প্রতিটি সারি এবং কলামে প্রদত্ত সমাধান গ্রিডের মতোই অআনোগ্রাফিক ম্যাগনুটিড থাকে।

উদাহরণস্বরূপ, পূর্ণ স্কোয়ার সহ একটি ননোগ্রাম গ্রিডের প্রতিটি সারি বা কলামে ননোগ্রাফিক মাত্রা 1 থাকে:

একটি 10x10 ননোগ্রাম যেখানে প্রতিটি স্কোয়ার পূরণ করা হয়।

গ্রিডের মাধ্যমে কেবল একটি তির্যক স্ট্রাইপ করে নাটকীয়ভাবে পূরণকৃত স্কোয়ারের সংখ্যা হ্রাস করেই একই অ্যানোগোগ্রাফিক মাত্রা অর্জন করা যেতে পারে:

উপরের মত একই অআনোগ্রাফিক परिमाण সহ একটি 10x10 ননગ્રામ


আপনার প্রোগ্রামটি এই ফাইলটি থেকে ( 50,000 লাইন সমন্বিত একটি ইনপুট পাবেন) (1.32 মেগাবাইট tar.gz পাঠ্য ফাইল; 2.15 এমবি আনজিপড), প্রতিটি এলোমেলোভাবে (80% কালো) ভরাট-ইন স্কোয়ার সহ একক 16 × 16 ননোগ্রোল সলিউশন গ্রিড উপস্থাপন করে এবং আরও 50,000 লাইন আউটপুট দিন, যার সাথে প্রতিটি সম্পর্কিত ইনপুট গ্রিডের জন্য অনুকূলিত দ্রবণ গ্রিড রয়েছে।

প্রতিটি গ্রিড একটি বেস 64 স্ট্রিং হিসাবে 43 টি অক্ষর (বাম থেকে ডানদিকে স্কোয়ারগুলি বাম থেকে ডানদিকে, নীচে থেকে নীচে) উপস্থাপিত হয় এবং আপনার প্রোগ্রামটিকে একই ফর্ম্যাটে তার আউটপুট ফিরিয়ে আনতে হবে। উদাহরণস্বরূপ, ফাইলে প্রথম গ্রিডটি হ'ল E/lu/+7/f/3rp//f799xn/9//2mv//nvj/bt/yc9/40=এবং এটি রেন্ডার করে:

প্রথম উদাহরণ ননোগ্রাম

গ্রিডটি Eকোন মানচিত্রের সাথে শুরু হয় 000100তাই শীর্ষ সারিতে প্রথম ছয়টি ঘরটি চতুর্থটি বাদে সমস্ত সাদা। পরবর্তী অক্ষরটি /কোনটি মানচিত্র করে 111111, তাই পরবর্তী, টি কক্ষগুলি সমস্ত কালো - এবং আরও কিছু so


আপনার প্রোগ্রামটি অবশ্যই 50,000 পরীক্ষার প্রতিটি ক্ষেত্রে সঠিক নোগোগ্রাফিক আকার সহ একটি সমাধান গ্রিডটি দিতে হবে। আরও ভাল কিছু না পাওয়া গেলে ইনপুট হিসাবে একই গ্রিডটি ফেরত দেওয়ার অনুমতি দেওয়া হয়।

সংক্ষিপ্ত মোট পূর্ণ স্কোয়ারগুলি (যে কোনও ভাষায়) ফেরত দেওয়ার প্রোগ্রামটি বিজয়ী, সংক্ষিপ্ত কোডটি টাইব্রেকার হিসাবে।


বর্তমান স্কোরবোর্ড:

  1. 3,637,260 - স্লেফার, জাভা
  2. 7,270,894 - ফ্লাওয়ার, মতলব
  3. 10,239,288 - জো জেড, বাশ

1
আমি বেস 64 এর এনকোডিংয়ের পয়েন্টটি সত্যই দেখতে পাচ্ছি না এবং এটির সাথে কাজ করা একটি আসল ব্যথা। কেবলমাত্র লাইনের এবং জিরোগুলি তৈরি করা কি সহজ হবে না? বা বিটম্যাপ হিসাবে পুরো জিনিস এনকোড?
flawr

@ ফ্লোয়ার: এটি ফাইলসাইজ হ্রাস করে, মূলত (মাত্র 1 এবং 0 এর তুলনায় 6 এর একটি ফ্যাক্টর দ্বারা)। এছাড়াও, বিটম্যাপগুলির সাথে কাজ করা আরও শক্ত হবে।
জো জেড।

আপনি কেবল একটি কালো এবং সাদা চিত্র তৈরি করতে পারেন, পড়তে / লিখতে সহজ এবং b64 এনকোডিংয়ের মতো একই আকার।
flawr

2
ইনপুট এবং / অথবা আউটপুট জন্য, b64 এনকোডিংয়ের একটি ভক্তও নয়। কেন কেবল আই / ও-কে কোনও সুবিধাজনক বিন্যাসে রাখবেন না?
স্পার 5

1
এটি ধরে নিলে, কালকের এই সময়ের মধ্যে আমার একটি সর্বোত্তম সমাধান হওয়া উচিত।
কুইন্টোপিয়া

উত্তর:


7

পাইথন 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 সলভ ননোগ্রাম গ্রিড রয়েছে (পঠনযোগ্য বিন্যাসে) রয়েছে যার প্রতিটি নীচে তালিকাভুক্ত মোট পূর্ণ সংখ্যা সহ।

আপনি যদি এর পরিবর্তে ভরা স্কোয়ারের সংখ্যাটি সর্বাধিক করতে চান তবে LpMinimize8 লাইনটি 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", এবং আরও অনেক কিছু। আমি গ্রিডের সমাধান অংশে কোষগুলির মধ্যে এবং তার আশেপাশে "স্পেসস" এর গ্রিডও তৈরি করি। rowseps289 ভেরিয়েবলগুলিকে নির্দেশ করে যা ফাঁকা স্থানগুলিকে প্রতীকী করে যা কোষগুলিকে অনুভূমিকভাবে পৃথক করে, অন্যদিকে 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

0S এবং গুলি দ্বারা ট্র্যাক বাইনারি মান 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 প্রায় কাছাকাছি এটি. বাকিরা কেবল ডিফল্ট সলভারকে আইএলপি সমাধানের জন্য জিজ্ঞাসা করে, তারপরে ফলাফলটি এটি ফাইলটিতে লেখার সাথে সাথে ফলাফলটি ফর্ম্যাট করে।


সত্যিই ভাল উত্তর। আমাকে এলপি সলভারগুলির সম্পর্কে জানতে চান। আপনি কি মনে করেন যে এটি 19x19, 6 রঙের বোর্ডের (কোনও সমাধানের গণনার সময় সম্পর্কিত ) বন্যার এটি ধাঁধা (লিঙ্ক) সমাধান করার জন্য ব্যবহার করা যেতে পারে ? আমি ইতিমধ্যে এই প্রতিযোগিতার উত্তর দিয়েছি (এবং এটি জিতেছি) তবে আমার পদ্ধতি (এ * অনুসন্ধানের অ্যালগরিদম) কেবলমাত্র অনুকূল সমাধান দেয় না।
tigrou

ধন্যবাদ আমি নিশ্চিত না যে বন্যার সমস্যাটি এমন সমাধান স্বীকার করার জন্য যথেষ্ট লিনিয়ার। আমি অবশ্যই এইভাবে এটির মডেলিং করতে পারি না।
কুইন্টোপিয়া

মনে হচ্ছে কারো ইতিমধ্যে এটা চেষ্টা: kunigami.blog/2012/09/16/flood-it-an-exact-approach তবে তাদের সাথে দেশের পারে 14x14 বোর্ডের জন্য সম্ভবপর সময়ের মধ্যে সন্তোষজনক সমাধান না।
tigrou

3

জাভা, 6,093,092 4,332,656 3,637,260 স্কোয়ার (ছোট করা), 10,567,550 10,567,691 10,568,746 স্কোয়ার (সর্বাধিক)

প্রোগ্রামের উভয় রূপগুলি বার বার প্রস্থ পরিবর্তন না করে উত্স গ্রিডে অপারেশন করে।

মিনিমাইজার

সঙ্কুচিত ()

এখানে চিত্র বর্ণনা লিখুন

যদি একটি কালো স্কোয়ারে 90 ° কোণে 2 সাদা প্রতিবেশী এবং 2 কালো প্রতিবেশী থাকে তবে এটি একটি সাদা স্কোয়ার দ্বারা প্রতিস্থাপন করা যেতে পারে।

moveLine ()

এখানে চিত্র বর্ণনা লিখুন এখানে চিত্র বর্ণনা লিখুন

কনফিগারেশনে কালো লাইনের উপরে ডানদিকে সরানো যেতে পারে। নতুন সঙ্কুচিত সম্ভাবনার খোলার জন্য ঘড়ির কাঁটার ও ঘড়ির কাঁটার বিপরীতে সমস্ত 4 লাইন দিকের জন্য এটি বারবার করা হয়।

Maximizer

লাইন Uncomment main()এই সংস্করণের জন্য উপরে লাইন আউট এবং মন্তব্য।

হত্তয়া ()

এখানে চিত্র বর্ণনা লিখুন

যদি কোনও সাদা স্কোয়ারে 90 ° কোণে 2 সাদা প্রতিবেশী এবং 2 কালো প্রতিবেশী থাকে তবে এটি একটি কালো স্কোয়ার দ্বারা প্রতিস্থাপন করা যেতে পারে।

moveLine ()

মিনিমাইজারের মতোই।

উৎস

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.Arrays;
import java.util.Base64;
import java.util.function.Function;

public class Main {
    private static final int SIZE = 16;
    private static final int SIZE_4 = SIZE + 4;
    private static final int E = 0;
    private static final int N = 1;
    private static final int W = 2;
    private static final int S = 3;

    private static final Base64.Decoder decoder = Base64.getMimeDecoder();
    private static final Base64.Encoder encoder = Base64.getMimeEncoder();
    private static int sourceBlack = 0;
    private static int targetBlack = 0;

    private static class Nonogram {
        private final boolean[] cells = new boolean[SIZE_4 * SIZE_4];
        private final int[] magnitudes;

        public Nonogram(String encoded) {
            super();
            byte[] decoded = decoder.decode(encoded);
            for (int i = 0; i < decoded.length; ++ i) {
                for (int j = 0; j < 8; ++ j) {
                    if ((decoded[i] & (1 << (7 - j))) != 0) {
                        int k = i * 8 + j;
                        cells[getPos(k / SIZE, k % SIZE)] = true;
                        ++ sourceBlack;
                    }
                }
            }
            magnitudes = calcMagnitudes();
        }

        private int getPos(int row, int col) {
            return (row + 2) * SIZE_4 + col + 2;
        }

        private int move(int pos, int dir, int count) {
            switch (dir) {
                case E: return pos + count;
                case N: return pos - count * SIZE_4;
                case W: return pos - count;
                case S: return pos + count * SIZE_4;
                default: return pos;
            }
        }

        private int move(int pos, int dir) {
            return move(pos, dir, 1);
        }

        private int[] calcMagnitudes() {
            int[] result = new int[SIZE * 2];
            for (int row = 0; row < SIZE; ++ row) {
                for (int col = 0; col < SIZE; ++ col) {
                    int pos = getPos(row, col);
                    if (cells[pos]) {
                        if (!cells[move(pos, W)]) {
                            ++ result[row + SIZE];
                        }
                        if (!cells[move(pos, N)]) {
                            ++ result[col];
                        }
                    }
                }
            }
            return result;
        }

        private boolean isBlack(int pos) {
            return cells[pos];
        }

        private boolean isWhite(int pos) {
            return !cells[pos];
        }

        private boolean allBlack(int pos, int dir, int count) {
            int p = pos;
            for (int i = 0; i < count; ++ i) {
                if (isWhite(p)) {
                    return false;
                }
                p = move(p, dir);
            }
            return true;
        }

        private boolean allWhite(int pos, int dir, int count) {
            int p = pos;
            for (int i = 0; i < count; ++ i) {
                if (isBlack(p)) {
                    return false;
                }
                p = move(p, dir);
            }
            return true;
        }

        private int findWhite(int pos, int dir) {
            int count = 0;
            int p = pos;
            while (cells[p]) {
                ++ count;
                p = move(p, dir);
            }
            return count;
        }

        @SafeVarargs
        private final void forEach(Function<Integer, Boolean>... processors) {
            outer:
            for (;;) {
                for (Function<Integer, Boolean> processor : processors) {
                    for (int row = 0; row < SIZE; ++ row) {
                        for (int col = 0; col < SIZE; ++ col) {
                            if (processor.apply(getPos(row, col))) {
                                continue outer;
                            }
                        }
                    }
                }
                return;
            }
        }

        private boolean shrink(int pos) {
            if (cells[pos] && cells[move(pos, W)] != cells[move(pos, E)] &&
                    cells[move(pos, N)] != cells[move(pos, S)]) {
                cells[pos] = false;
                return true;
            }
            return false;
        }

        private boolean grow(int pos) {
            if (!cells[pos] && cells[move(pos, W)] != cells[move(pos, E)] &&
                    cells[move(pos, N)] != cells[move(pos, S)]) {
                cells[pos] = true;
                return true;
            }
            return false;
        }

        private boolean moveLine(boolean clockwise, int dir, int sourcePos) {
            int from = (dir + (clockwise ? 1 : 3)) % 4;
            int to = (dir + (clockwise ? 3 : 1)) % 4;
            int opp = (dir + 2) % 4;
            if (isBlack(sourcePos) && isWhite(move(sourcePos, from)) && isWhite(move(sourcePos, dir))) {
                int toCount = findWhite(move(move(sourcePos, dir), to), to) + 1;
                if (allWhite(move(sourcePos, to), to, toCount + 1)) {
                    int lineCount = 1;
                    int tmpPos = move(sourcePos, opp);
                    while (isBlack(tmpPos) && isWhite(move(tmpPos, from)) && allWhite(move(tmpPos, to),  to, toCount + 1)) {
                        ++ lineCount;
                        tmpPos = move(tmpPos, opp);
                    }
                    if (allBlack(tmpPos, to, toCount + 1)) {
                        tmpPos = sourcePos;
                        for (int j = 0; j < lineCount; ++ j) {
                            cells[tmpPos] = false;
                            cells[move(tmpPos, to, toCount)] = true;
                            tmpPos = move(tmpPos, opp);
                        }
                        return true;
                    }
                }
            }
            return false;
        }

        public Nonogram minimize() {
            for (int i = 0; i < 5; ++ i) {
                forEach(pos -> shrink(pos), pos -> moveLine(true, E, pos), pos -> moveLine(true, N, pos),
                        pos -> moveLine(true, W, pos), pos -> moveLine(true, S, pos));
                forEach(pos -> shrink(pos), pos -> moveLine(false, E, pos), pos -> moveLine(false, N, pos),
                        pos -> moveLine(false, W, pos), pos -> moveLine(false, S, pos));
            }
            return this;
        }

        public Nonogram maximize() {
            for (int i = 0; i < 5; ++ i) {
                forEach(pos -> grow(pos), pos -> moveLine(true, E, pos), pos -> moveLine(true, N, pos),
                        pos -> moveLine(true, W, pos), pos -> moveLine(true, S, pos));
                forEach(pos -> grow(pos), pos -> moveLine(false, E, pos), pos -> moveLine(false, N, pos),
                        pos -> moveLine(false, W, pos), pos -> moveLine(false, S, pos));
            }
            return this;
        }

        public String toBase64() {
            if (!Arrays.equals(magnitudes, calcMagnitudes())) {
                throw new RuntimeException("Something went wrong!");
            }
            byte[] decoded = new byte[SIZE * SIZE / 8];
            for (int i = 0; i < decoded.length; ++ i) {
                for (int j = 0; j < 8; ++ j) {
                    int k = i * 8 + j;
                    if (cells[getPos(k / SIZE, k % SIZE)]) {
                        decoded[i] |= 1 << (7 - j);
                        ++ targetBlack;
                    }
                }
            }
            return encoder.encodeToString(decoded);
        }

        @Override
        public String toString() {
            StringBuilder b = new StringBuilder();
            for (int row = 0; row < SIZE; ++ row) {
                for (int col = 0; col < SIZE; ++ col) {
                    b.append(cells[getPos(row, col)] ? '#' : ' ');
                }
                b.append('\n');
            }
            return b.toString();
        }
    }

    public static void main(String[] args) throws Exception {
        try (BufferedWriter writer = new BufferedWriter(new FileWriter("solutions_b64.txt"));
                BufferedReader reader = new BufferedReader(new FileReader("nonograms_b64.txt"))) {
            String line;
            while ((line = reader.readLine()) != null) {
                writer.write(new Nonogram(line).minimize().toBase64() + "\n");
                //writer.write(new Nonogram(line).maximize().toBase64() + "\n");
            }
        }
        System.out.printf("%d -> %d", sourceBlack, targetBlack);
    }
}

1

বাশ - 10,239,288 স্কোয়ার

একটি শেষ স্থান রেফারেন্স সমাধান হিসাবে:

cp nonograms_b64.txt solutions_b64.txt

যেহেতু আপনার প্রোগ্রামটি আরও ভাল সমাধান না খুঁজে পেতে একই গ্রিডটি ফেরত দেওয়ার অনুমতি দেওয়া হয়েছে, তাই পুরো ফাইলটি ভারব্যাটিমের মুদ্রণও বৈধ।

পরীক্ষার ফাইলে মোট 10,239,288 টি ব্ল্যাক স্কোয়ার রয়েছে যা 10,240,000 এর কাছাকাছি যেটি আপনি প্রত্যাশা করতেন যে 25,000 স্কোয়ার সহ 50,000 গ্রিডের মধ্যে 80% স্কোয়ার পূরণ করা হবে। আমার টেস্ট-ব্যাটারির প্রশ্নগুলির মতো যথারীতি, আমি সর্বোত্তম স্কোর 2 মিলিয়ন পরিসরের আশেপাশে থাকবে এমন প্রত্যাশা নিয়ে পরীক্ষার কেসের সংখ্যাটি নির্বাচন করেছি, যদিও আমার সন্দেহ এইবারের স্কোরগুলি 4 বা 5 মিলিয়নের কাছাকাছি থাকবে suspect ।


যদি কেউ এমন কোনও সমাধান তৈরি করতে পারেন যা কালো স্কোয়ারগুলি হ্রাস করার পরিবর্তে সর্বাধিক করে তোলে এবং 10,240,000 এরও বেশি পরিচালিত করে, আমি এটিকে অনুগ্রহ দেওয়ার বিষয়টি বিবেচনা করতে পারি।


1

মতলব, 7,270,894 স্কোয়ার (মূলের ~ 71%)

আইডিয়া একটি সাধারণ পুনরাবৃত্তি লোভী অনুসন্ধান: প্রতিটি কালো বর্গক্ষেত্রের জন্য, যদি আপনি অচিকিত্সার দৈর্ঘ্য পরিবর্তন না করে এটি সাদাতে সেট করতে পারেন তবে চেষ্টা করুন। এটি দু'বার পুনরাবৃত্তি করুন। (আপনি আরও পুনরাবৃত্তির সাহায্যে আরও ভাল ফলাফল অর্জন করতে পারেন তবে নিখরচায় নয়: এটি ফলস্বরূপ দীর্ঘকালীন রানটাইমের সময় হয়ে যায় Now এখন এটি প্রায় ৮০ মিনিট ছিল I আমি যদি এটি করতে পারি, যদি আমাদের সমস্ত ৫০ কে টেস্টকেসগুলি গণনা না করে ...)

এখানে কোড (যথারীতি পৃথক ফাইলে প্রতিটি ফাংশন))

function D = b64decode(E)
% accepts a string of base 64 encoded data, and returns a array of zeros
% and ones
F = E;
assert( mod(numel(E),4)==0 && 0 <= sum(E=='=') && sum(E=='=') <= 2,'flawed base 64 code')

F('A' <= E & E<= 'Z') = F('A' <= E & E<= 'Z') -'A';       %upper case
F('a' <= E & E<= 'z') = F('a' <= E & E<= 'z') -'a' + 26;  %lower case
F('0'<= E & E <= '9') = F('0'<= E & E <= '9') -'0' + 52;  %digits
F( E == '+') = 62;
F( E == '/') = 63;
F( E == '=') = 0;

D=zeros(1,numel(E)*3*8/4);

for k=1:numel(E);
    D(6*(k-1)+1 + (0:5)) = dec2bin(F(k),6)-'0';
end

if E(end) == '=';
    D(end-7:end) = [];
    if E(end-1) == '=';
        D(end-7:end) = [];
    end
end
end

function E = b64encode(D)
assert(mod(numel(D),8)==0,'flawed byte code');
N=0;
while mod(numel(D),6) ~= 0;
    D = [D,zeros(1,8)];
    N = N+1;
end
dict = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

E=zeros(1,numel(D)/6)+'=';
for k=0:numel(E)-N-1;
    E(k+1) = dict(bin2dec( [D(6*k+(1:6))+'0',''] ) + 1);
end

E = [E,''];
end


function [B,T,O] = reduce_greedy(N)
% reduce greedily
NM = nomographic_magnitude(N);
B = N; %current best
M = N;
T = nnz(N); %current number of filled squares
O = T;

for r=1:2;  %how many repetitions
    I = find(B);
    for k=1:numel(I);
        M = B;
        M( I(k) ) = 0;
        %check whether we have a valid solution
        if all(NM == nomographic_magnitude(M))
            if T > nnz(M); %did we actually reduce the number of filled squares?
                B = M;
                T = nnz(M);
            end
        end
    end
end


%% main file
string_in = fileread('nonograms_b64.txt');
string_out = string_in;
tic
total_new = 0;  %total number of black squares
total_old = 0;
M = 50000;
for k=1:M;
    disp(k/M); %display the progress
    line = string_in(45*(k-1)+(1:44));
    decoded = b64decode(line);        
    nonogram = reshape(decoded,16,[]) ;%store nonogram as a matrix
    [B,T,O] = reduce_greedy(nonogram);
    disp([nnz(B),nnz(nonogram)])
    total_new = total_new + T;
    total_old = total_old + O;
    string_in(45*(k-1)+(1:44)) = b64encode(B(:).');
end
toc
F = fopen('nonograms_b64_out.txt','w');
fprintf(F,string_out);
%%
disp([total_new,total_old])
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.