বিপুল সংখ্যক উপ-সমস্যা সহ গতিময় প্রোগ্রামিং


11

বিপুল সংখ্যক উপ-সমস্যা সহ গতিময় প্রোগ্রামিং। তাই আমি ইন্টারভিউ স্ট্রিট থেকে এই সমস্যাটি সমাধান করার চেষ্টা করছি:

গ্রিড ওয়াকিং (স্কোর 50 পয়েন্ট)
আপনি অবস্থানে একটি ডাইমেনশনাল গ্রিডে রয়েছেন । গ্রিডের মাত্রা )। এক ধাপে, আপনি যে কোনও মাত্রার মধ্যে এক ধাপ এগিয়ে বা পিছনে যেতে পারেন । (সুতরাং সর্বদা সম্ভাব্য বিভিন্ন পদক্ষেপ থাকে)। আপনি কতগুলি উপায়ে পদক্ষেপ নিতে পারেন যে আপনি কোনও পর্যায়ে গ্রিডটি ছাড়েন না? আপনি যে কোনো যদি গ্রিড ছেড়ে , হয় বা ।N(x1,x2,,xN)(D1,D2,,DNN2NMxixi0xi>Di

আমার প্রথম চেষ্টাটি ছিল এই স্মৃতিযুক্ত পুনরাবৃত্ত সমাধান:

def number_of_ways(steps, starting_point):
    global n, dimensions, mem
    #print steps, starting_point
    if (steps, tuple(starting_point)) in mem:
        return mem[(steps, tuple(starting_point))]
    val = 0
    if steps == 0:
        val = 1
    else:
        for i in range(0, n):
            tuple_copy = starting_point[:]
            tuple_copy[i] += 1
            if tuple_copy[i] <= dimensions[i]:
                val += number_of_ways(steps - 1, tuple_copy)
            tuple_copy = starting_point[:]
            tuple_copy[i] -= 1
            if tuple_copy[i] > 0:
                val += number_of_ways(steps - 1, tuple_copy)
    mem[(steps, tuple(starting_point))] = val
    return val

বড় অবাক: স্মৃতির অভাবের কারণে এটি প্রচুর পদক্ষেপ এবং / বা মাত্রা ব্যর্থ হয়।

সুতরাং পরবর্তী পদক্ষেপটি ডায়নামিক প্রোগ্রামিং ব্যবহার করে আমার সমাধানটি উন্নত করা। তবে শুরু করার আগে, আমি পদ্ধতির সাথে একটি বড় সমস্যা দেখছি। যুক্তি starting_pointএকটি হল -tuple, যেখানে যত বড় । সুতরাং প্রকৃতপক্ষে, ফাংশনটি সাথে থাকতে পারে ।n 10 1 x i100nn10number_of_ways(steps, x1, x2, x3, ... x10)1xi100

পাঠ্যপুস্তকগুলিতে আমি যে ডায়নামিক প্রোগ্রামিং সমস্যাগুলি দেখেছি সেগুলির প্রায় সকলেরই দ্বিগুণ ভেরিয়েবল রয়েছে, যাতে কেবলমাত্র দ্বি-মাত্রিক ম্যাট্রিক্সের প্রয়োজন হয়। এই ক্ষেত্রে, দশ-মাত্রিক ম্যাট্রিক্সের প্রয়োজন হবে। সুতরাং মোট কোষ।10010

ডায়নামিক প্রোগ্রামিং-এ 2-ডি ম্যাট্রিক্স সহ, পরবর্তী গণনার জন্য সাধারণত পূর্বের সারি গণনার প্রয়োজন হয়, তাই স্থানিক জটিলতা থেকে হ্রাস করে । আমি নিশ্চিত না যে এই ক্ষেত্রে আমি কীভাবে এটি করব। কোনও টেবিলটি দৃশ্যমান করা সম্ভব নয়, সুতরাং উপরের পুনরাবৃত্তি থেকে উত্তরটি সরাসরি আসতে হবে।mnmin(m,n)

হালনাগাদ

পিটার শোরের পরামর্শগুলি ব্যবহার করে এবং কিছু ছোটখাটো সংশোধন করা, বিশেষত ফাংশনে অবস্থানের উপর নজর রাখার প্রয়োজন , এবং কেবল মাত্র দুটি সেট এ এবং বি বিভক্তকরণের পরিবর্তে বিভাজনকে কার্যকরভাবে ব্যবহার করে বিভাজন এবং বিজয় পদ্ধতি, একটি বেস কেস না পৌঁছানো পর্যন্ত যেখানে কেবলমাত্র একটি মাত্রা সেট থাকে।W(i,ti)

আমি নিম্নলিখিত বাস্তবায়ন নিয়ে এসেছি, যা সর্বোচ্চ কার্যকরকরণের সময়ের নীচে সমস্ত পরীক্ষায় উত্তীর্ণ হয়েছিল:

def ways(di, offset, steps):
    global mem, dimensions
    if steps in mem[di] and offset in mem[di][steps]:
        return mem[di][steps][offset]
    val = 0
    if steps == 0:
        val = 1
    else:
        if offset - 1 >= 1:
            val += ways(di, offset - 1, steps - 1)
        if offset + 1 <= dimensions[di]:
            val += ways(di, offset + 1, steps - 1)
    mem[di][steps][offset] = val
    return val


def set_ways(left, right, steps):
    # must create t1, t2, t3 .. ti for steps
    global mem_set, mem, starting_point
    #print left, right
    #sleep(2)
    if (left, right) in mem_set and steps in mem_set[(left, right)]:
        return mem_set[(left, right)][steps]
    if right - left == 1:
        #print 'getting steps for', left, steps, starting_point[left]
        #print 'got ', mem[left][steps][starting_point[left]], 'steps'
        return mem[left][steps][starting_point[left]]
        #return ways(left, starting_point[left], steps)
    val = 0
    split_point =  left + (right - left) / 2 
    for i in xrange(steps + 1):
        t1 = i
        t2 = steps - i
        mix_factor = fact[steps] / (fact[t1] * fact[t2])
        #print "mix_factor = %d, dimension: %d - %d steps, dimension %d - %d steps" % (mix_factor, left, t1, split_point, t2)
        val += mix_factor * set_ways(left, split_point, t1) * set_ways(split_point, right, t2)
    mem_set[(left, right)][steps] = val
    return val

import sys
from time import sleep, time

fact = {}
fact[0] = 1
start = time()
accum = 1
for k in xrange(1, 300+1):
    accum *= k
    fact[k] = accum
#print 'fact_time', time() - start

data = sys.stdin.readlines()
num_tests = int(data.pop(0))
for ignore in xrange(0, num_tests):
    n_and_steps = data.pop(0)
    n, steps = map(lambda x: int(x), n_and_steps.split())
    starting_point = map(lambda x: int(x), data.pop(0).split())
    dimensions = map(lambda x: int(x), data.pop(0).split())
    mem = {}
    for di in xrange(n):
        mem[di] = {}
        for i in xrange(steps + 1):
            mem[di][i] = {}
            ways(di, starting_point[di], i)
    start = time()
    #print 'mem vector is done'
    mem_set = {}
    for i in xrange(n + 1):
        for j in xrange(n + 1):
            mem_set[(i, j)] = {}
    answer = set_ways(0, n, steps)
    #print answer
    print answer % 1000000007
    #print time() - start

2
"এটি প্রচুর পদক্ষেপ এবং / বা মাত্রার জন্য ব্যর্থ" - এখানে "ব্যর্থ" এর অর্থ কী?
রাফেল

1
স্বাগত! আমি আপনার প্রশ্নটি সম্পাদিত করেছি ক) যথাযথ মার্কডাউন এবং ল্যাটেক্স ফর্ম্যাটিং ব্যবহার করুন (ভবিষ্যতে নিজেকে দয়া করে করুন) এবং খ) অতিরিক্ত অতিরিক্ত নালী অপসারণ করুন। আমরা সি কোডের অস্পষ্টতাগুলির যত্ন নিই না; দয়া করে নিজেকে ধারণার মধ্যে সীমাবদ্ধ করুন , এটি কেন্দ্রীয় বিষয়গুলির সিউডো কোড।
রাফেল

ব্যর্থতার অর্থ এটি অভিধানটি পূরণ করে সমস্ত উপলব্ধ সিস্টেমের মেমোরিটিকে ক্লান্ত করে mem[]। এবং আমার উত্তর পরিষ্কার করার জন্য আপনাকে ধন্যবাদ। ল্যাটেক্সের সাথে খুব বেশি পরিচিত না কিন্তু পরের বার চেষ্টা করবেন।
আলেকজান্দ্রে

আপনি সম্পাদক বক্সের পাশে মার্কডাউনে সহায়তা পেতে পারেন; ল্যাটেক্সে প্রাইমারের জন্য এখানে দেখুন ।
রাফেল

উত্তর:


14

বিভিন্ন মাত্রা স্বাধীন । আপনি যা করতে পারেন তা হ'ল প্রতিটি মাত্রা j এর জন্য কতগুলি বিভিন্ন পদচারণ রয়েছে কেবলমাত্র সেই মাত্রায় যা পদক্ষেপ নেয়। আসুন আমরা সেই নাম্বারে কল করি । আপনার প্রশ্ন থেকে, আপনি ইতিমধ্যে জানেন কীভাবে ডায়নামিক প্রোগ্রামিংয়ের সাথে এই সংখ্যাগুলি গণনা করতে হয়।tW(j,t)

, মাত্রা অনুসারে পদক্ষেপ পদক্ষেপের সংখ্যা গণনা করা সহজ । আপনার কাছে মাত্রা যাতে মাত্রা গৃহীত পদক্ষেপ মোট সংখ্যা interspersing পথ হয় , এবং এই উপায়ে প্রতিটি আপনি দিয়ে হেঁটে যাচ্ছে। এই ওভার যোগফল পেতে এখন, মেমরিটি নিয়ন্ত্রণে রয়েছে, যেহেতু আপনাকে কেবল মানগুলি মনে রাখা দরকার । সময়টি বড় জন্য অতিপরিবর্তনীয়ভাবে বৃদ্ধি পায় তবে বেশিরভাগ কম্পিউটারের স্মৃতি থেকে অনেক বেশি সময় থাকে।tii(Nt1,t2,,tM)itiΠ1NW(i,ti)

t1+t2++tN=M(Mt1,t2,,tN) Πi=1NW(i,ti).
W(j,t)N

আপনি আরও ভাল করতে পারেন। মাত্রাগুলিকে পুনরাবৃত্তভাবে দুটি উপগঠন, এবং বিভক্ত করুন এবং কতগুলি হাঁটাচলাগুলি উপসেট র মাত্রাগুলি এবং কেবল ব্যবহার করছেন তা গণনা করুন । এই নম্বরগুলিতে এবং কল করুন । আপনি হাঁটতে মোট সংখ্যা পাবেনABABWA(t)WB(t)

t1+t2=M(Mt1)WA(t1)WB(t2).

হে পিটার. ঠিক আছে, এটি অনুপস্থিত অন্তর্দৃষ্টি ছিল। এখন আমার কেবল একটি সন্দেহ বাকি আছে। বাহ্যিক সমষ্টি টি 1, টি 2, ... tn এর সমস্ত সম্ভাব্য সংমিশ্রণগুলিতে পুনরাবৃত্তি করে যা এম এর সমষ্টি, দুর্ভাগ্যক্রমে, এই জাতীয় সংমিশ্রনের সংখ্যা সি (এম + 1, এন-1), যা সি (300) -র বেশি হতে পারে +1, 10-9)। খুব বড় সংখ্যা ... :(
আলেকজান্দ্রে

1
@ অ্যালেক্সানড্রে: আমার দ্বিতীয় অ্যালগরিদম ("আপনি আরও ভাল করতে পারেন" দিয়ে শুরু করে) এতে সমস্যা নেই। আমি আমার উত্তরে প্রথম অ্যালগরিদম রেখেছি কারণ এটিই প্রথম আমি নিয়ে এসেছি এবং কারণ আমি মনে করি যে দ্বিতীয় অ্যালগরিদমকে কোনও প্রেরণা না দিয়ে দেওয়ার চেয়ে প্রথমটির বৈকল্প হিসাবে ব্যাখ্যা করা আরও সহজ easier
পিটার শর

আমি দ্বিতীয় অ্যালগরিদম প্রয়োগ করেছি। এটি দ্রুত, তবে বৃহত্তম সীমাটির জন্য এখনও খুব কম। প্রথমটির সমস্যাটি টি 1, টি 2, টি 3, ... টিএন এর সমস্ত সম্ভাব্য সংস্থার উপর পুনরাবৃত্তি হয়েছিল যা এম এর সমষ্টি হিসাবে চিহ্নিত হয়েছিল দ্বিতীয় এলগরিদমটি কেবল টি 1 + টি 2 = এম এর সমাধানগুলিতে পুনরাবৃত্তি করে তবে তারপরে একই হবে ওয়া (t1), টি 1 '+ টি 2' = টি 1 এর সমাধানগুলিতে পুনরাবৃত্তি হচ্ছে। এবং তাই পুনরাবৃত্তি। আপনার আগ্রহী হওয়ার ক্ষেত্রে এখানে বাস্তবায়নটি রয়েছে: পেস্টবিন . com/e1 বিএলজি 7 জি কে । এবং দ্বিতীয় অ্যালগরিদমে, মাল্টিনোমিয়াল টি এম 1 এর বেশি হওয়া উচিত, টি 2 নং?
আলেকজান্দ্রে

কিছু মনে করো না! সমাধান! সেট_ওয়ে ফাংশনে মেমোইজেশন ব্যবহার করতে হয়েছিল। এখানে চূড়ান্ত সমাধান, যা দ্রুত জ্বলছে! পেস্টবিন.com/ জিএনকেজেজেপিবিএন আপনার অন্তর্দৃষ্টি পিটারের জন্য আপনাকে ধন্যবাদ। আপনি উভয় মূল পর্যবেক্ষণ করেছেন: সমস্যার স্বাধীনতা এবং বিভাজন এবং বিজয়। আমি লোকদের আমার সমাধানটি দেখার পরামর্শ দিচ্ছি কারণ কিছু জিনিস রয়েছে যা উপরের উত্তরে নেই, যেমন ডাব্লু (আই, টিআই) ফাংশনটির তৃতীয় যুক্তির প্রয়োজন, যা অবস্থান। I, ti এবং অবস্থানের মান সংমিশ্রণের জন্য এটি গণনা করতে হবে। আপনি যদি পারেন তবে আপনার দ্বিতীয় অ্যালগরিদমে মাল্টিনোমিয়াল টি 2 যোগ করুন।
আলেকজান্দ্রে

4

আসুন আপনার কোড থেকে এর সূত্রটি বের করুন (কোনও অভ্যন্তরীণ কক্ষে, যা সীমান্তের মামলাগুলি উপেক্ষা করছে):now(s,x1,,xn)

now(s,x1,,xn)=+i=0nnow(s1,x1,,xi1,xi+1,xi+1,,xn)+i=0nnow(s1,x1,,xi1,xi1,xi+1,,xn)

এখানে কিছু ধারনা.

  • আমরা দেখতে পাচ্ছি যে আপনি একবার জন্য সমস্ত মান গণনা করলে আপনি জন্য সমস্ত গণিত মান ফেলে দিতে পারেন ।s=ks<k
  • একটি নির্দিষ্ট জন্য , আপনি টেবিল এন্ট্রি lexicographic অনুক্রমে (ঠিক কারণ এটা সাধারণ) গনা করা উচিত নয়। তারপরে, নোট করুন যে প্রতিটি কোষকে কেবলমাত্র "একের ব্যাসার্ধ" এর মধ্যে এমন কক্ষগুলির প্রয়োজন হয়, এটি কোনও স্থানাঙ্কের চেয়ে বেশি দূরে হতে পারে can সুতরাং, একবারে আপনার পুনরাবৃত্তিটি হিট হয়ে গেলে আপনি জন্য সমস্ত মান ফেলে দিতে পারেন । যদি এটি পর্যাপ্ত না হয় তবে জন্যও একই করুন - ফিক্সড , এবং পৌঁছে গেলে মানগুলি ড্রপ করুন - ইত্যাদি।sx1=ix1i2x2x1=ix1=ix2j2x2=j
  • নোট যে, "তাই সবসময় সম্ভব বিভিন্ন প্যাচসমূহ" শুধুমাত্র গ্রিড মাঝখানে ঝুলিতে হয় যে যদি এবং সবার জন্য । তবে এর অর্থ হ'ল উত্তরটি মাঝখানে সহজ: এটি ঠিক । । যদি আপনার একটি কার্যকরী গতিশীল প্রোগ্রামিং পুনরাবৃত্তি ঘটে থাকে তবে তা একাই আপনাকে বেশিরভাগ টেবিলটি শেভ করতে দেয় (যদি )।2NxiM>0xi+M<Dii(2N)MMN
  • আরেকটি বিষয় লক্ষণীয় যে আপনাকে পুরো টেবিলটি গণনা করতে হবে না; বেশিরভাগ মান দিয়ে পূরণ করা হবে (যদি )। আপনি চারপাশে প্রান্ত দৈর্ঘ্য এর (হাইপার) কিউবে নিজেকে সীমাবদ্ধ করতে পারেন (নোট করুন যে গ্রিডটি ছেড়ে যাওয়ার পথে এটি নষ্ট হবে)।0MN2Mx

এটি মেমরির ব্যবহার বেশ কম রাখতে যথেষ্ট হবে should


হাই রাফেল, ধরা যাক আমাদের লক্ষ্যটি এখন (3, 3, 3, 3) গ্রিড 5x5x5 এ রয়েছে। আপনার পরামর্শ অনুসারে ডায়নামিক প্রোগ্রামিং এবং লেক্স অর্ডার ব্যবহার করে, আমরা এখন গণনা করব (0, 0, 0, 0), তারপরে (0, 0, 0, 1), ... এখন (0, 5, 5, 5)। কোন মুহুর্তে আমরা এখন (0, 0, 0, 0) বাতিল করতে পারি (যা (5, 5, 5) থেকে একের বেশি ব্যাসার্ধের চেয়ে বেশি, যেহেতু এখন আমাদের এখন এটি গণনা করা প্রয়োজন (1, 0, 0 , 0), এখন (1, 0, 0, 1), ইত্যাদি? আপনি কয়েকবার এম << এন উল্লেখ করেছেন, তবে সীমাটি 1 <= এম <= 300, এবং 1 <= এন <= 10. সুতরাং , চূড়ান্তভাবে, এটি 1 << 300. বলে মনে হচ্ছে না
আলেকজান্ডার

1) আমার দ্বিতীয় বুলেটটি অস্পষ্ট কি? যত তাড়াতাড়ি আপনি গণনা করবেন , আপনি বাতিল করতে পারেন । এটি সেই প্রাথমিক পয়েন্ট নয় যেখানে আপনি বাতিল করতে পারেন , যদিও; আপনার সর্বশেষ সেলটির জন্য এটি প্রয়োজন । 2) আমি এবং জন্য আপনার নির্দিষ্ট মানগুলি সম্পর্কে খুব বেশি উদ্বিগ্ন নই , সত্যি বলতে to আমি বরং সাধারণ সমস্যাটি দেখতে চাই। আপনার যদি না থাকে তবে শেষ দুটি বুলেট আপনাকে বেশি সাহায্য করবে না। এবং এর প্রভাবটি লক্ষ্য করার জন্য পর্যাপ্ত হওয়া উচিত, এবং কোনও কৌশলই কখনই ব্যথা করে না। (2,0,0,0)(0,\*,\*,\*)(0,0,0,0)(1,0,0,0)MNMNM=1N=10
রাফায়েল

1
1) বুলেট আমি বুঝতে। এটি এম * ডি ^ এন থেকে ডি ^ এন থেকে স্থানিক জটিলতা হ্রাস করে তবে ডি ^ এন এখনও অনেক বেশি। আমি যদিও দেখতে পাচ্ছি না 2) বুলেটটি কীভাবে কাজ করে। আপনি কি আমার মন্তব্যে উদাহরণটি উদাহরণস্বরূপ ব্যবহার করতে পারেন?
আলেকজান্দ্রে

@ আলেকজান্দ্রে আমি আমার আগের মন্তব্যে করেছিলাম। আমি যদি meaning অর্থ হিসাবে পড়ি , তবে দ্বিতীয় বুলেটটি একবার to এর সাথে স্পেস জটিলতা হ্রাস করে , দ্বিতীয়বার এবং শীঘ্রই. (আরও স্পষ্টভাবে, এটি থেকে এবং আরও যায়))Dmaxi=1,,NDiDN1DN2i=1NDii=2NDi
রাফেল

কীভাবে এটি করা যায় তা মোটামুটি উপলব্ধি করা যায় না ... আসুন আমি বলি যে আমি বুঝতে পেরেছিলাম, এবং আমি যে ডিস্টিওটিভ জটিলতাটি মূলত ডি তে পরিণত করেছি, এম * ডি ^ এন সাব-সমস্যাগুলি এখনও সমাধান করার দরকার নেই? সমস্যাটি বহুপদী তৈরি করার জন্য কি অতিরিক্ত সম্পত্তির প্রয়োজন নেই?
আলেকজান্দ্রে
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.