এই সমস্যাটি দেখতে, আমি একটি পূর্ণসংখ্যা প্রোগ্রামিং ফ্রেমওয়ার্ক ব্যবহার করব এবং সিদ্ধান্ত ভেরিয়েবলের তিনটি সেট নির্ধারণ করব:
- x_ij : আমরা জলের অবস্থান (i, j) এ ব্রিজ তৈরি করি কিনা এর জন্য একটি বাইনারি সূচক পরিবর্তনশীল।
- y_ijbcn : জলের অবস্থান (i, j) দ্বীপ খ সাথে দ্বীপকে সংযোগকারী n ^ ম অবস্থান যা কিনা তার জন্য একটি বাইনারি সূচক।
- l_bc : দ্বীপপুঞ্জের বি এবং সি সরাসরি যুক্ত রয়েছে কিনা এর জন্য একটি বাইনারি সূচক পরিবর্তনশীল (ওরফে আপনি কেবল ব্রিজ স্কোয়ারে বি থেকে সি পর্যন্ত হাঁটতে পারবেন)।
ব্রিজ বিল্ডিংয়ের জন্য সি_আইজি ব্যয় হয়, হ্রাস করার উদ্দেশ্যগত মানটি sum_ij c_ij * x_ij
। আমাদের মডেলটিতে নিম্নলিখিত সীমাবদ্ধতাগুলি যুক্ত করতে হবে:
- আমাদের নিশ্চিত করতে হবে y_ijbcn ভেরিয়েবল বৈধ কিনা। আমরা যদি সেখানে সেতু তৈরি করি তবে আমরা কেবলমাত্র জলের স্কোয়ারে পৌঁছে যেতে পারি, তাই
y_ijbcn <= x_ij
প্রতিটি জলের অবস্থানের (i, j) জন্য। আরও, y_ijbc1
যদি (i, j) দ্বীপ বি সীমানা না করে তবে অবশ্যই 0 এর সমান হতে হবে। অবশেষে, এন> 1 এর জন্য, y_ijbcn
কেবলমাত্র যদি প্রতিবেশী জলের অবস্থানটি পদক্ষেপ এন -1 ব্যবহার করা হত। N(i, j)
জলের স্কোয়ারগুলি প্রতিবেশী (i, j) হিসাবে সংজ্ঞায়িত করা, এটি সমান y_ijbcn <= sum_{(l, m) in N(i, j)} y_lmbc(n-1)
।
- আমাদের নিশ্চিত করতে হবে l_bc ভেরিয়েবলগুলি কেবলমাত্র খ এবং সি লিঙ্কযুক্ত থাকলে সেট করা আছে। যদি আমরা
I(c)
দ্বীপ সীমান্তবর্তী অবস্থানগুলি হিসাবে সংজ্ঞায়িত করি তবে এটি সম্পন্ন করা যেতে পারে l_bc <= sum_{(i, j) in I(c), n} y_ijbcn
।
- আমাদের নিশ্চিত করতে হবে যে সমস্ত দ্বীপ প্রত্যক্ষ বা পরোক্ষভাবে সংযুক্ত রয়েছে। এটি নিম্নলিখিত উপায়ে সম্পন্ন করা যেতে পারে: দ্বীপগুলির প্রতিটি অ-খালি যথাযথ উপসেট এসের জন্য, এস এর কমপক্ষে একটি দ্বীপ কমপক্ষে একটি দ্বীপের সাথে সংযুক্ত থাকে যা এস এর পরিপূরক হয়, যাকে আমরা এস 'বলব। সীমাবদ্ধতায়, আমরা আকারের প্রতিটি খালি খালি সেট এস এর জন্য সীমাবদ্ধতা যোগ করে এটি প্রয়োগ করতে পারি <= কে / 2 (যেখানে কে দ্বীপের সংখ্যা)
sum_{b in S} sum_{c in S'} l_bc >= 1
,।
কে দ্বীপপুঞ্জ, ডাব্লু জলের বর্গক্ষেত্র এবং সুনির্দিষ্ট সর্বাধিক পাথ দৈর্ঘ্যের এনগুলির ক্ষেত্রে সমস্যার জন্য, এটি O(K^2WN)
ভেরিয়েবল এবং O(K^2WN + 2^K)
সীমাবদ্ধতার সাথে একটি মিশ্র পূর্ণসংখ্যা প্রোগ্রামিং মডেল । স্পষ্টতই সমস্যাটির আকার বড় হওয়ার সাথে সাথে এটি অচল হয়ে উঠবে, তবে আপনি যে আকারের সেগুলি আকারের জন্য এটি সমাধানযোগ্য হতে পারে। স্কেলাবিলিটির ধারণাটি পেতে, আমি সজ্জা প্যাকেজটি ব্যবহার করে অজগরটিতে এটি প্রয়োগ করব। আসুন প্রথমে প্রশ্নটির নীচে 3 দ্বীপপুঞ্জের সাথে ছোট 7 x 9 মানচিত্র দিয়ে শুরু করি:
import itertools
import pulp
water = {(0, 2): 2.0, (0, 3): 1.0, (0, 4): 1.0, (0, 5): 1.0, (0, 6): 2.0,
(1, 0): 2.0, (1, 1): 9.0, (1, 2): 1.0, (1, 3): 9.0, (1, 4): 9.0,
(1, 5): 9.0, (1, 6): 1.0, (1, 7): 9.0, (1, 8): 2.0,
(2, 0): 1.0, (2, 1): 9.0, (2, 2): 9.0, (2, 3): 1.0, (2, 4): 9.0,
(2, 5): 1.0, (2, 6): 9.0, (2, 7): 9.0, (2, 8): 1.0,
(3, 0): 9.0, (3, 1): 1.0, (3, 2): 9.0, (3, 3): 9.0, (3, 4): 5.0,
(3, 5): 9.0, (3, 6): 9.0, (3, 7): 1.0, (3, 8): 9.0,
(4, 0): 9.0, (4, 1): 9.0, (4, 2): 1.0, (4, 3): 9.0, (4, 4): 1.0,
(4, 5): 9.0, (4, 6): 1.0, (4, 7): 9.0, (4, 8): 9.0,
(5, 0): 9.0, (5, 1): 9.0, (5, 2): 9.0, (5, 3): 2.0, (5, 4): 1.0,
(5, 5): 2.0, (5, 6): 9.0, (5, 7): 9.0, (5, 8): 9.0,
(6, 0): 9.0, (6, 1): 9.0, (6, 2): 9.0, (6, 6): 9.0, (6, 7): 9.0,
(6, 8): 9.0}
islands = {0: [(0, 0), (0, 1)], 1: [(0, 7), (0, 8)], 2: [(6, 3), (6, 4), (6, 5)]}
N = 6
# Island borders
iborders = {}
for k in islands:
iborders[k] = {}
for i, j in islands[k]:
for dx in [-1, 0, 1]:
for dy in [-1, 0, 1]:
if (i+dx, j+dy) in water:
iborders[k][(i+dx, j+dy)] = True
# Create models with specified variables
x = pulp.LpVariable.dicts("x", water.keys(), lowBound=0, upBound=1, cat=pulp.LpInteger)
pairs = [(b, c) for b in islands for c in islands if b < c]
yvals = []
for i, j in water:
for b, c in pairs:
for n in range(N):
yvals.append((i, j, b, c, n))
y = pulp.LpVariable.dicts("y", yvals, lowBound=0, upBound=1)
l = pulp.LpVariable.dicts("l", pairs, lowBound=0, upBound=1)
mod = pulp.LpProblem("Islands", pulp.LpMinimize)
# Objective
mod += sum([water[k] * x[k] for k in water])
# Valid y
for k in yvals:
i, j, b, c, n = k
mod += y[k] <= x[(i, j)]
if n == 0 and not (i, j) in iborders[b]:
mod += y[k] == 0
elif n > 0:
mod += y[k] <= sum([y[(i+dx, j+dy, b, c, n-1)] for dx in [-1, 0, 1] for dy in [-1, 0, 1] if (i+dx, j+dy) in water])
# Valid l
for b, c in pairs:
mod += l[(b, c)] <= sum([y[(i, j, B, C, n)] for i, j, B, C, n in yvals if (i, j) in iborders[c] and B==b and C==c])
# All islands connected (directly or indirectly)
ikeys = islands.keys()
for size in range(1, len(ikeys)/2+1):
for S in itertools.combinations(ikeys, size):
thisSubset = {m: True for m in S}
Sprime = [m for m in ikeys if not m in thisSubset]
mod += sum([l[(min(b, c), max(b, c))] for b in S for c in Sprime]) >= 1
# Solve and output
mod.solve()
for row in range(min([m[0] for m in water]), max([m[0] for m in water])+1):
for col in range(min([m[1] for m in water]), max([m[1] for m in water])+1):
if (row, col) in water:
if x[(row, col)].value() > 0.999:
print "B",
else:
print "-",
else:
print "I",
print ""
সজ্জা প্যাকেজ (সিবিসি সলভার) থেকে ডিফল্ট সল্ভার ব্যবহার করে চালাতে 1.4 সেকেন্ড সময় লাগে এবং সঠিক সমাধানটি আউটপুট করে:
I I - - - - - I I
- - B - - - B - -
- - - B - B - - -
- - - - B - - - -
- - - - B - - - -
- - - - B - - - -
- - - I I I - - -
এরপরে, প্রশ্নের শীর্ষে পুরো সমস্যাটি বিবেচনা করুন, যা 7 টি দ্বীপযুক্ত 13 x 14 গ্রিড:
water = {(i, j): 1.0 for i in range(13) for j in range(14)}
islands = {0: [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0), (2, 1)],
1: [(9, 0), (9, 1), (10, 0), (10, 1), (10, 2), (11, 0), (11, 1),
(11, 2), (12, 0)],
2: [(0, 7), (0, 8), (1, 7), (1, 8), (2, 7)],
3: [(7, 7), (8, 6), (8, 7), (8, 8), (9, 7)],
4: [(0, 11), (0, 12), (0, 13), (1, 12)],
5: [(4, 10), (4, 11), (5, 10), (5, 11)],
6: [(11, 8), (11, 9), (11, 13), (12, 8), (12, 9), (12, 10), (12, 11),
(12, 12), (12, 13)]}
for k in islands:
for i, j in islands[k]:
del water[(i, j)]
for i, j in [(10, 7), (10, 8), (10, 9), (10, 10), (10, 11), (10, 12),
(11, 7), (12, 7)]:
water[(i, j)] = 20.0
N = 7
এমআইপি সল্ভকারীরা প্রায়শই তুলনামূলকভাবে দ্রুত ভাল সমাধান পান এবং তারপরে সমাধানটির অনুকূলতাকে প্রমাণ করার জন্য প্রচুর সময় ব্যয় করেন। উপরের মত একই সলভার কোড ব্যবহার করে, প্রোগ্রামটি 30 মিনিটের মধ্যেই শেষ হয় না। তবে, আপনি আনুমানিক সমাধান পেতে সলভারটির একটি সময়সীমা সরবরাহ করতে পারেন:
mod.solve(pulp.solvers.PULP_CBC_CMD(maxSeconds=120))
এটি উদ্দেশ্যগত মান 17 সহ একটি সমাধান দেয়:
I I - - - - - I I - - I I I
I I - - - - - I I - - - I -
I I - - - - - I - B - B - -
- - B - - - B - - - B - - -
- - - B - B - - - - I I - -
- - - - B - - - - - I I - -
- - - - - B - - - - - B - -
- - - - - B - I - - - - B -
- - - - B - I I I - - B - -
I I - B - - - I - - - - B -
I I I - - - - - - - - - - B
I I I - - - - - I I - - - I
I - - - - - - - I I I I I I
আপনি যে সমাধানগুলি পেয়েছেন তার মান বাড়ানোর জন্য, আপনি বাণিজ্যিক এমআইপি সলভার ব্যবহার করতে পারেন (আপনি যদি কোনও একাডেমিক প্রতিষ্ঠানে থাকেন এবং সম্ভবত অন্যথায় বিনামূল্যে না হন) এটি বিনামূল্যে is উদাহরণস্বরূপ, আবার 2 মিনিটের সময়সীমা সহ গুরোবি 6.0.4 এর পারফরম্যান্স (যদিও সমাধান লগ থেকে আমরা পড়লাম যে সল্ভারটি 7 সেকেন্ডের মধ্যে বর্তমানের সেরা সমাধানটি খুঁজে পেয়েছে):
mod.solve(pulp.solvers.GUROBI(timeLimit=120))
এটি প্রকৃতপক্ষে অবজেক্টিভ ভ্যালু 16 এর সমাধান খুঁজে পায়, ওপি হাতের সাহায্যে খুঁজে পেতে সক্ষম হয়ে তার চেয়ে ভাল better
I I - - - - - I I - - I I I
I I - - - - - I I - - - I -
I I - - - - - I - B - B - -
- - B - - - - - - - B - - -
- - - B - - - - - - I I - -
- - - - B - - - - - I I - -
- - - - - B - - B B - - - -
- - - - - B - I - - B - - -
- - - - B - I I I - - B - -
I I - B - - - I - - - - B -
I I I - - - - - - - - - - B
I I I - - - - - I I - - - I
I - - - - - - - I I I I I I