একটি ব্যয়-পথের সমাধান রয়েছে তবে আপনাকে এটি নিজের কোড করতে হবে। প্রশ্নের চিত্রের প্রতিটি পয়েন্টে প্রয়োগ করার সময় এটি দেখতে কেমন লাগবে তা এখানে (গণনার গতি বাড়ানোর জন্য কিছুটা মোটা করা):
কৃষ্ণকোষগুলি আশেপাশের বহুভুজগুলির অংশ। হালকা কমলা (সংক্ষিপ্ত) থেকে নীল (দীর্ঘ) মাধ্যমে রঙগুলি, সর্বাধিক দূরত্ব (সর্বাধিক 50 কোষের বাইরে) দেখায় যা বহুভুজ কোষগুলি বাধা না দিয়ে লাইন অফ দর্শনীয় ট্র্যাভারসাল দ্বারা পৌঁছানো যায়। (এই চিত্রের সীমার বাইরে যে কোনও ঘরকে বহুভুজগুলির অংশ হিসাবে বিবেচনা করা হয়))
আসুন এটি করার একটি কার্যকরী উপায় নিয়ে ডেটাটির উপস্থাপক উপস্থাপনা ব্যবহার করে আলোচনা করি। এই উপস্থাপনায় সমস্ত "পার্শ্ববর্তী" বহুভুজ কোষের, বলুন, ননজারো মান এবং যে কোনও ঘর যা "মাধ্যমে দেখা যায়" তার শূন্য মান হবে।
পদক্ষেপ 1: একটি প্রতিবেশী ডেটা কাঠামো প্রাক্কলন করা
আপনাকে প্রথমে সিদ্ধান্ত নিতে হবে যে একটি কক্ষের জন্য অন্য কোনও ব্লককে কী বোঝায়। আমি খুঁজে পেতে পারি এমন সবচেয়ে নিখুঁত নিয়মগুলির মধ্যে একটি হ'ল: সারি এবং কলামগুলির জন্য অবিচ্ছেদ্য স্থানাঙ্কগুলি ব্যবহার করে (এবং বর্গক্ষেত্রগুলি অনুমান করে), আসুন বিবেচনা করা যাক কোন কোষগুলি সেল (i, j) কে অরিজিনের (0,0) ভিউ থেকে আটকাতে পারে। আমি ঘরটি (i ', j') মনোনীত করি যা লাইন বিভাগের নিকটবর্তী (i, j) থেকে (0,0) সংযুক্ত হয় এমন সমস্ত কোষের মধ্যে যার স্থানাঙ্কগুলি i এবং j এর চেয়ে বেশি 1 এর চেয়ে আলাদা হয় কারণ এটি সর্বদা নয় একটি অনন্য সমাধান উত্পন্ন করুন (উদাহরণস্বরূপ, (i, j) = (1,2) উভয় (0,1) এবং (1,1) সমানভাবে ভাল কাজ করবে), সম্পর্কগুলি সমাধানের জন্য কিছু উপায়ের প্রয়োজন। গ্রিডগুলির মধ্যে বিজ্ঞপ্তি প্রতিবেশগুলির প্রতিসাম্যগুলির প্রতি সম্মান জানাতে সম্পর্কের এই রেজোলিউশনটির জন্য চমৎকার হবে: স্থানাঙ্কগুলিকে সমন্বয় করা বা স্যুইচিং করা এই পাড়াগুলি সংরক্ষণ করে। সুতরাং আমরা সিদ্ধান্ত নিতে পারি কোন কোষগুলি ব্লক করে (i,
এই বিধিটি চিত্রিত করে নীচে লেখা প্রোটোটাইপ কোড R
। এই কোডটি এমন একটি ডেটা কাঠামো দেয় যা গ্রিডে স্বেচ্ছাসেবী কোষগুলির "চারপাশে" নির্ধারণের জন্য সুবিধাজনক হবে।
screen <- function(k=1) {
#
# Returns a data structure:
# $offset is an array of offsets
# $screened is a parallel array of screened offset indexes.
# $distance is a parallel array of distances.
# The first index always corresponds to (0,0).
#
screened.by <- function(xy) {
uv <- abs(xy)
if (reversed <- uv[2] > uv[1]) {
uv <- rev(uv)
}
i <- which.min(c(uv[1], abs(uv[1]-uv[2]), uv[2]))
ij <- uv + c(floor((1-i)/3), floor(i/3)-1)
if (reversed) ij <- rev(ij)
return(ij * sign(xy))
}
#
# For each lattice point within the circular neighborhood,
# find the unique lattice point that screens it from the origin.
#
xy <- subset(expand.grid(x=(-k:k), y=(-k:k)),
subset=(x^2+y^2 <= k^2) & (x != 0 | y != 0))
g <- t(apply(xy, 1, function(z) c(screened.by(z), z)))
#
# Sort by distance from the origin.
#
colnames(g) <- c("x", "y", "x.to", "y.to")
ij <- unique(rbind(g[, 1:2], g[, 3:4]))
i <- order(abs(ij[,1]), abs(ij[,2])); ij <- ij[i, , drop=FALSE]
rownames(ij) <- 1:length(i)
#
# Invert the "screened by" relation to produce the "screened" relation.
#
# (Row, column) offsets.
ij.df <- data.frame(ij, i=1:length(i))
#
# Distances from the origin (in cells).
distance <- apply(ij, 1, function(u) sqrt(sum(u*u)))
#
# "Screens" relation (represented by indexes into ij).
g <- merge(merge(g, ij.df), ij.df,
by.x=c("x.to", "y.to"), by.y=c("x","y"))
g <- subset(g, select=c(i.x, i.y))
h <- by(g$i.y, g$i.x, identity)
return( list(offset=ij, screened=h, distance=distance) )
}
এর screen(12)
স্ক্রিনিং সম্পর্কের এই চিত্রটি তৈরি করতে এর মান ব্যবহৃত হত: তীরগুলি সেগুলি থেকে সেগুলি নির্দেশ করে যা তত্ক্ষণাত তাদের স্ক্রীন করে। বর্ণগুলি মূলটির দূরত্ব অনুসারে অনুপাত করা হয়, যা এই পাড়ার মাঝখানে অবস্থিত:
এই গণনাটি দ্রুত এবং প্রদত্ত প্রতিবেশীর জন্য একবারে করা দরকার। উদাহরণস্বরূপ, 5 মিটার সেল সহ গ্রিডে 200 মিটার সন্ধান করার সময়, পার্শ্ববর্তী আকারটি 200/5 = 40 ইউনিট হবে।
পদক্ষেপ 2: নির্বাচিত পয়েন্টগুলিতে গণনা প্রয়োগ করা
বাকিগুলি সোজা: এই প্রতিবেশী ডেটা কাঠামোর ক্ষেত্রে (x, y) (সারি এবং কলাম স্থানাঙ্কের) অবস্থিত একটি ঘর "ঘিরে" আছে কিনা তা নির্ধারণ করার জন্য, পরীক্ষাটি পুনরাবৃত্তভাবে (i, j) এর অফসেট দিয়ে শুরু করুন = (0,0) (আশেপাশের উত্স)। (X, y) + (i, j) এ বহুভুজ গ্রিডের মান যদি ননজারো হয় তবে সেখানে দৃশ্যমানতা অবরুদ্ধ থাকে। অন্যথায়, আমাদের সমস্ত অফসেটগুলি বিবেচনা করতে হবে যা অফসেটে অবরুদ্ধ করা যেতে পারে (i, j) (যেগুলি O (1) এর মাধ্যমে প্রাপ্ত ডেটা কাঠামো ব্যবহার করে সময় পাওয়া যায় screen
)। যদি অবরুদ্ধ কোনও কিছুই না থাকে তবে আমরা ঘেরে পৌঁছে গিয়ে পৌঁছেছি যে (x, y) চারপাশে নেই, তাই আমরা গণনাটি বন্ধ করি (এবং আশেপাশের কোনও অবশিষ্ট পয়েন্ট পরিদর্শন করতে বিরক্ত করব না)।
অ্যালগরিদমের সময় সর্বাধিক দূরবর্তী দৃষ্টির দূরত্বের ট্র্যাক রেখে আমরা আরও দরকারী তথ্য সংগ্রহ করতে পারি। এটি যদি কাঙ্ক্ষিত ব্যাসার্ধের চেয়ে কম হয় তবে ঘরটি ঘিরে থাকে; অন্যথায় এটি হয় না।
R
এই অ্যালগরিদমের একটি প্রোটোটাইপ এখানে । এটি মনে হয় তার চেয়ে বেশি দীর্ঘ, কারণ R
পুনরাবৃত্তি বাস্তবায়নের জন্য প্রয়োজনীয় (সহজ) স্ট্যাক কাঠামোটি স্থানীয়ভাবে সমর্থন করে না, তাই একটি স্ট্যাককেও কোডিং করতে হবে। আসল অ্যালগরিদম প্রায় দুই তৃতীয়াংশ পথ দিয়ে শুরু হয় এবং তার জন্য মাত্র এক ডজন লাইন প্রয়োজন। (এবং তাদের অর্ধেকগুলি কেবল গ্রিডের প্রান্তের চারপাশের পরিস্থিতি পরিচালনা করে, পার্শ্ববর্তী অঞ্চলে সীমার বাইরে থাকা সূচিগুলির জন্য অনুসন্ধান করে। বহুভুজ গ্রিডটিকে k
তার ঘেরের চারপাশে সারি এবং কলামগুলি প্রসারিত করে আরও কার্যকর করা যায় , যেকোনও সমস্যা দূর করে inating বহুভুজ গ্রিডটি ধরে রাখতে আরও কয়েকটি র্যামের দামে সূচক পরিসীমা চেক করা দরকার))
#
# Test a grid point `ij` for a line-of-sight connection to the perimeter
# of a circular neighborhood.
# `xy` is the grid.
# `counting` determines whether to return max distance or count of stack ops.
# `perimeter` is the assumed values beyond the extent of `xy`.
#
# Grid values of zero admit light; all others block visibility
# Returns maximum line-of-sight distance found within `nbr`.
#
panvisibility <- function(ij, xy, nbr=screen(), counting=FALSE, perimeter=1) {
#
# Implement a stack for the algorithm.
#
count <- 0 # Stack count
stack <- list(ptr=0, s=rep(NA, dim(nbr$offset)[1]))
push <- function(x) {
n <- length(x)
count <<- count+n # For timing
stack$s[1:n + stack$ptr] <<- x
stack$ptr <<- stack$ptr+n
}
pop <- function() {
count <<- count+1 # For timing
if (stack$ptr <= 0) return(NULL)
y <- stack$s[stack$ptr]
#stack$s[stack$ptr] <<- NA # For debugging
stack$ptr <<- stack$ptr - 1
return(y)
}
#
# Initialization.
#
m <- dim(xy)[1]; n <- dim(xy)[2]
push(1) # Stack the *indexes* of nbr$offset and nbr$screened.
dist.max <- -1
#
# The algorithm.
#
while (!is.null(i <- pop())) {
cell <- nbr$offset[i, ] + ij
if (cell[1] <= 0 || cell[1] > m || cell[2] <= 0 || cell[2] > n) {
value <- perimeter
} else {
value <- xy[cell[1], cell[2]]
}
if (value==0) {
if (nbr$distance[i] > dist.max) dist.max <- nbr$distance[i]
s <- nbr$screened[[paste(i)]]
if (is.null(s)) {
#exited = TRUE
break
}
push(s)
}
}
if (counting) return ( count )
return(dist.max)
}
এই উদাহরণে, বহুভুজ কোষগুলি কালো। দীর্ঘতম দূরত্বের জন্য স্বল্প দূরত্বের থেকে হালকা কমলা থেকে গা dark় নীল পর্যন্ত রঙগুলি সর্বাধিক লাইন অফ দর্শনীয় দূরত্ব (50 কোষের বাইরে) দেয় non (কোষগুলি এক একক প্রশস্ত এবং উচ্চতর)) দৃশ্যমান স্পষ্ট লাইনগুলি "নদীর" মাঝখানে ছোট বহুভুজ "দ্বীপপুঞ্জ" দ্বারা তৈরি করা হয়েছিল: প্রত্যেকে অন্য কোষের দীর্ঘ লাইনকে অবরুদ্ধ করে।
অ্যালগরিদমের বিশ্লেষণ
স্ট্যাকের গঠন কার্যকরী প্রমাণ একটি সেল হয় আশপাশ দৃশ্যমানতা গ্রাফ গভীরতায়-প্রথম সার্চ না বেষ্টিত। যেখানে কোষগুলি কোনও বহুভুজ থেকে অনেক দূরে রয়েছে, এই অনুসন্ধানের জন্য ব্যাসার্ধ-কে বৃত্তাকার প্রতিবেশের জন্য কেবল ও (কে) কোষগুলির পরিদর্শন প্রয়োজন। সবচেয়ে খারাপ পরিস্থিতি তখন ঘটে যখন আশেপাশে খুব কম সংখ্যক ছড়িয়ে ছিটিয়ে বহুভুজ কোষ থাকে তবে তবুও প্রতিবেশীর সীমানা পৌঁছানো যায় না: এগুলিতে প্রতিটি পাড়ার প্রায় সমস্ত কক্ষ পরিদর্শন করা প্রয়োজন যা একটি হে (কে ^ 2) অপারেশন.
নিম্নলিখিত আচরণটি যা সম্মুখীন হবে তা সাধারণ। কে এর ছোট মানগুলির জন্য, বহুভুজগুলি বেশিরভাগ গ্রিড পূরণ না করে, বেশিরভাগ নন-বহুভুজ কোষগুলি স্পষ্টতই অসম্পূর্ণ হবে এবং ও (কে) এর মতো অ্যালগোরিদম স্কেলগুলি। মধ্যবর্তী মানগুলির জন্য, স্কেলিংটি ও (কে ^ 2) এর মতো দেখতে শুরু হয়। যেহেতু কে সত্যিই বড় আকার ধারণ করেছে, বেশিরভাগ কোষকে ঘিরে রাখা হবে এবং পুরো পাড়াটি পরিদর্শন করার আগে এই বাস্তবতাটি ভালভাবে নির্ধারণ করা যেতে পারে: অ্যালগরিদমের গণনার প্রচেষ্টা যার ফলে ব্যবহারিক সীমাতে পৌঁছে যায়। এই সীমাটি তখনই পাওয়া যায় যখন গ্রিডের বৃহত্তম সংযুক্ত অ-বহুভুজীয় অঞ্চলের ব্যাসার কাছাকাছি ব্যাসার্ধটি পৌঁছায়।
উদাহরণস্বরূপ, আমি প্রতিটি কলে ব্যবহৃত স্ট্যাক অপারেশনগুলির সংখ্যা ফিরিয়ে দেওয়ার জন্য counting
প্রোটোটাইপটিতে কোডড বিকল্পটি ব্যবহার করি screen
। এটি গণনার প্রচেষ্টা পরিমাপ করে। নিম্নলিখিত গ্রাফটি প্রতিবেশী ব্যাসার্ধের ক্রিয়া হিসাবে স্ট্যাক অপের গড় সংখ্যাকে প্লট করে। এটি পূর্বাভাসিত আচরণ প্রদর্শন করে।
আমরা গ্রিডে 13 মিলিয়ন পয়েন্ট মূল্যায়নের জন্য প্রয়োজনীয় গণনাটি অনুমান করতে এটি ব্যবহার করতে পারি। মনে করুন যে কে = 200/5 = 40 এর একটি পাড়া ব্যবহার করা হয়েছে। তারপরে গড়ে কয়েক শতাধিক স্ট্যাক অপারেশন প্রয়োজন হবে (বহুভুজ গ্রিডের জটিলতার উপর নির্ভর করে এবং যেখানে বহুভুজগুলির তুলনায় ১৩ মিলিয়ন পয়েন্ট রয়েছে) এটি বোঝায় যে একটি দক্ষ সংকলিত ভাষায়, কমপক্ষে কয়েক হাজার সরল সংখ্যাসূচক ক্রিয়াকলাপ প্রয়োজন হবে (যোগ, গুণ, পড়া, লিখুন, অফসেট, ইত্যাদি)। বেশিরভাগ পিসি সেই হারে প্রায় দশ মিলিয়ন পয়েন্টের আশেপাশের মূল্যায়ন করতে সক্ষম হবে। (দ্যR
বাস্তবায়ন এর চেয়ে অনেক ধীর, কারণ এ ধরণের অ্যালগরিদমে এটি ক্ষীণ, কারণ এটিকে কেবল প্রোটোটাইপ হিসাবে বিবেচনা করা যেতে পারে)) তদনুসারে, আমরা আশা করতে পারি যে একটি যুক্তিসঙ্গত দক্ষ এবং উপযুক্ত ভাষায় একটি কার্যকর বাস্তবায়ন - সি ++ এবং পাইথন মাথায় আসে - পুরো বহুভুজ গ্রিডটি র্যামে থাকে বলে ধরে নিয়ে এক মিনিট বা তারও কম সময়ে 13 মিলিয়ন পয়েন্টের মূল্যায়ন সম্পন্ন করতে পারে ।
যখন কোনও গ্রিডটি র্যামের সাথে ফিট করার জন্য খুব বড় হয়, এই পদ্ধতিটি গ্রিডের টাইল অংশগুলিতে প্রয়োগ করা যেতে পারে। তাদের কেবল k
সারি এবং কলামগুলিতে ওভারল্যাপ করতে হবে ; ফলাফলগুলি মোসাক করার সময় ওভারল্যাপে ম্যাক্সিমা নিন।
অন্যান্য অ্যাপ্লিকেশন
জল একটি শরীরের "আনা" ঘনিষ্ঠভাবে তার পয়েন্ট "surroundedness" সাথে সম্পর্কিত হয়। প্রকৃতপক্ষে, আমরা যদি ওয়াটারবডি ব্যাসের সমান বা তার চেয়েও বেশি আশেপাশের ব্যাসার্ধ ব্যবহার করি তবে আমরা জলরক্ষার প্রতিটি পয়েন্টে (অ-দিকনির্দেশক) আনার গ্রিড তৈরি করব। একটি ছোট প্রতিবেশী ব্যাসার্ধ ব্যবহার করে আমরা কমপক্ষে সমস্ত সর্বোচ্চ-আনয়ন পয়েন্টগুলিতে আনার জন্য নিম্ন সীমাটি অর্জন করব, যা কিছু অ্যাপ্লিকেশনগুলিতে যথেষ্ট ভাল হতে পারে (এবং এটি গণনার প্রচেষ্টাকে হ্রাস করতে পারে)। এই অ্যালগরিদমের একটি বৈকল্পিক যা নির্দিষ্ট দিকগুলির সাথে সম্পর্কিত "স্ক্রিন করা" সীমাবদ্ধ করে সেই দিকগুলিতে দক্ষতার সাথে আনার গণনা করার এক উপায় হবে। নোট করুন যে এই ধরণের রূপগুলির জন্য কোডটি সংশোধন করা প্রয়োজন screen
; কোডটি panvisibility
মোটেও বদলায় না।