প্রদত্ত নোড থেকে / নির্দেশিত গ্রাফের সমস্ত চক্রটি কীভাবে (পুনরাবৃত্তি হবে) খুঁজে পেতে পারি?
উদাহরণস্বরূপ, আমি এই জাতীয় কিছু চাই:
A->B->A
A->B->C->A
তবে তা নয়: বি-> সি-> বি
প্রদত্ত নোড থেকে / নির্দেশিত গ্রাফের সমস্ত চক্রটি কীভাবে (পুনরাবৃত্তি হবে) খুঁজে পেতে পারি?
উদাহরণস্বরূপ, আমি এই জাতীয় কিছু চাই:
A->B->A
A->B->C->A
তবে তা নয়: বি-> সি-> বি
উত্তর:
আমি এই পৃষ্ঠাটি আমার সন্ধানে পেয়েছি এবং যেহেতু চক্রগুলি দৃ strongly়ভাবে সংযুক্ত উপাদানগুলির মতো নয়, তাই আমি অনুসন্ধান চালিয়ে যাচ্ছি এবং শেষ পর্যন্ত, আমি একটি কার্যকর অ্যালগরিদম পেয়েছি যা নির্দেশিত গ্রাফের সমস্ত (প্রাথমিক) চক্রকে তালিকাভুক্ত করে। এটি ডোনাল্ড বি জনসনের এবং পেপারটি নিম্নলিখিত লিঙ্কটিতে পাওয়া যাবে:
http://www.cs.tufts.edu/comp/150GA/homeworks/hw1/Johnson%2075.PDF
একটি জাভা বাস্তবায়ন পাওয়া যাবে:
http://normalisiert.de/code/java/elementaryCycles.zip
জনসনের অ্যালগরিদমের একটি গণিতের প্রদর্শন এখানে পাওয়া যাবে , বাস্তবায়ন ডান থেকে ডাউনলোড করা যেতে পারে ( "লেখকের কোড ডাউনলোড করুন" )।
দ্রষ্টব্য: আসলে এই সমস্যার জন্য অনেকগুলি অ্যালগরিদম রয়েছে। তাদের কিছু এই নিবন্ধে তালিকাভুক্ত করা হয়েছে:
http://dx.doi.org/10.1137/0205007
নিবন্ধ অনুসারে, জনসনের অ্যালগরিদম দ্রুততম।
A->B->C->A
প্রাথমিকও নয়?
simple_cycle
নেটওয়ার্কেক্স হিসাবে প্রয়োগ করা হয়েছে।
ব্যাকট্র্যাকিংয়ের সাথে গভীরতার প্রথম অনুসন্ধান এখানে কাজ করা উচিত। আপনি কোনও নোড আগে গেছেন কিনা তা ট্র্যাক রাখতে বুলিয়ান মানগুলির একটি অ্যারে রাখুন। আপনি যদি যেতে নতুন নোডের বাইরে চলে যান (কোনও নোড না ফেলে আপনি ইতিমধ্যে গেছেন) তবে কেবল ব্যাকট্র্যাক করুন এবং একটি ভিন্ন শাখা চেষ্টা করুন try
আপনার যদি গ্রাফ উপস্থাপনের জন্য সংলগ্ন তালিকা থাকে তবে ডিএফএস কার্যকর করা সহজ। উদাহরণস্বরূপ [অ্যা] = {বি, সি} নির্দেশ করে যে বি এবং সি এ এর সন্তান are
উদাহরণস্বরূপ, নীচে সিউডো-কোড। "শুরু" হ'ল নোড যা থেকে আপনি শুরু করেন।
dfs(adj,node,visited):
if (visited[node]):
if (node == start):
"found a path"
return;
visited[node]=YES;
for child in adj[node]:
dfs(adj,child,visited)
visited[node]=NO;
স্টার্ট নোড দিয়ে উপরের ফাংশনটি কল করুন:
visited = {}
dfs(adj,start,visited)
if (node == start):
- node and start
প্রথম কলটিতে কী আছে
start
) জড়িত সমস্ত চক্র খুঁজে বের করবে । এটি সেই শীর্ষবিন্দু থেকে শুরু হয় এবং ডিএফএস করে যতক্ষণ না এটি আবার সেই শীর্ষবিন্দুতে ফিরে আসে, তারপরে এটি জানে যে এটি একটি চক্র খুঁজে পেয়েছে। তবে এটি আসলে চক্রগুলি আউটপুট দেয় না, কেবল তাদের মধ্যে একটি গণনা (তবে এটি করার জন্য এটি পরিবর্তন করা খুব কঠিন হওয়া উচিত নয়)।
start
। আপনাকে সত্যিকার অর্থে পরিদর্শন করা ফ্ল্যাগগুলি সাফ করার দরকার নেই কারণ প্রতিটি ভিজিট করা পতাকা কারণে সাফ হবে visited[node]=NO;
। তবে মনে রাখবেন যে আপনার যদি একটি চক্র থাকে তবে আপনি A->B->C->A
এটি 3 বার সনাক্ত start
করতে পারবেন, এর মধ্যে যে কোনও 3 হতে পারে। এটি রোধ করার জন্য একটি ধারণা হ'ল আরেকটি পরিদর্শন করা অ্যারে যেখানে প্রতিটি নোড যা start
কোনও কোনও মুহুর্তে নোড সেট করা থাকে এবং তারপরে আপনি এগুলি পুনর্বিবেচনা করবেন না।
প্রথমত - আপনি আক্ষরিকভাবে সমস্ত চক্রটি সন্ধান করতে চান না কারণ যদি সেখানে 1 হয় তবে সেইগুলির একটি অসীম সংখ্যা রয়েছে। উদাহরণস্বরূপ এবিএ, আব্বা ইত্যাদি বা 2 টি চক্রকে 8-জাতীয় চক্র ইত্যাদিতে একসাথে যুক্ত করা সম্ভব হতে পারে ইত্যাদি ইত্যাদি ... অর্থবোধক পদ্ধতির মধ্যে রয়েছে সমস্ত তথাকথিত সহজ চক্রগুলি অনুসন্ধান করা - যাঁরা নিজেকে অতিক্রম করে না তারা ব্যতীত শুরু / শেষ পয়েন্টে তারপরে আপনি যদি চান তবে আপনি সাধারণ চক্রের সংমিশ্রণ তৈরি করতে পারেন।
নির্দেশিত গ্রাফের সমস্ত সহজ চক্র সন্ধানের জন্য বেসলাইন অ্যালগরিদমগুলির মধ্যে একটি হ'ল: গ্রাফের সমস্ত সহজ পাথ (যারা নিজেরাই অতিক্রম করে না) একটি গভীরতার প্রথম ট্রভারসালাল করুন। প্রত্যেকবার যখন বর্তমান নোডের স্ট্যাকের উত্তরসূরি রয়েছে তখন একটি সাধারণ চক্র আবিষ্কার করা হয়। এটি স্ট্যাকের উপাদানগুলিকে চিহ্নিত উত্তরসূরির সাথে শুরু করে এবং স্ট্যাকের শীর্ষে সমাপ্ত হয়। সমস্ত সাধারণ পাথের গভীরতা প্রথম ট্র্যাভারসাল গভীরতা প্রথম অনুসন্ধানের সমান তবে আপনি স্ট্যাক পয়েন্ট হিসাবে বর্তমানে স্ট্যাকের বাইরে অন্য কোনও ভিজিট নোডগুলি চিহ্নিত / রেকর্ড করেন না।
উপরের ব্রুট ফোর্স অ্যালগরিদম মারাত্মকভাবে অদক্ষ এবং এটি ছাড়াও চক্রের একাধিক অনুলিপি তৈরি করা হয়। এটি তবে একাধিক ব্যবহারিক অ্যালগরিদমের শুরুতে যা কর্মক্ষমতা উন্নত করতে এবং চক্রের সদৃশতা এড়াতে বিভিন্ন বর্ধিতকরণ প্রয়োগ করে। আমি কিছু সময় আগে অবাক হয়ে জানতে পারি যে এই অ্যালগরিদমগুলি পাঠ্যপুস্তক এবং ওয়েবে সহজেই পাওয়া যায় না। সুতরাং আমি এখানে কিছু মুক্ত গবেষণা করেছি এবং একটি মুক্ত উত্স জাভা লাইব্রেরিতে অনির্দেশিত গ্রাফগুলিতে চক্রের জন্য এই জাতীয় 4 টি অ্যালগরিদম এবং 1 অ্যালগরিদম বাস্তবায়ন করেছি: http://code.google.com/p/niographs/ ।
বিটিডাব্লু, যেহেতু আমি অপ্রচলিত গ্রাফ উল্লেখ করেছি: সেগুলির জন্য অ্যালগরিদম আলাদা। একটি বিস্তৃত গাছ তৈরি করুন এবং তারপরে গাছের অংশ নয় এমন প্রতিটি প্রান্ত গাছের কয়েকটি প্রান্তের সাথে একসাথে একটি সাধারণ চক্র গঠন করে। এই পথে পাওয়া চক্রগুলি তথাকথিত চক্র বেস তৈরি করে। 2 বা ততোধিক স্বতন্ত্র বেস চক্রকে একত্রিত করে সমস্ত সাধারণ চক্রগুলি পাওয়া যায়। আরও তথ্যের জন্য দেখুন: উদাহরণস্বরূপ: http://dspace.mit.edu/bitstream/handle/1721.1/68106/FTL_R_1982_07.pdf ।
jgrapht
হয় যা ব্যবহার করা হয় http://code.google.com/p/niographs/
আপনার কাছ থেকে উদাহরণ নিতে পারেন github.com/jgrapht/jgrapht/wiki/DirectedGraphDemo
এই সমস্যাটি সমাধান করার জন্য আমি যে সহজ পছন্দটি পেয়েছি তা হ'ল পাইথন লাইব নামে পরিচিত networkx
।
এটি এই প্রশ্নের উত্তরের উত্তরে উল্লিখিত জনসনের অ্যালগরিদম প্রয়োগ করে তবে তা কার্যকর করা সহজ করে তোলে।
সংক্ষেপে আপনার নিম্নলিখিত প্রয়োজন:
import networkx as nx
import matplotlib.pyplot as plt
# Create Directed Graph
G=nx.DiGraph()
# Add a list of nodes:
G.add_nodes_from(["a","b","c","d","e"])
# Add a list of edges:
G.add_edges_from([("a","b"),("b","c"), ("c","a"), ("b","d"), ("d","e"), ("e","a")])
#Return a list of cycles described as a list o nodes
list(nx.simple_cycles(G))
উত্তর: [['এ', 'বি', 'ডি', 'ই'], ['এ', 'বি', 'সি']]
nx.DiGraph({'a': ['b'], 'b': ['c','d'], 'c': ['a'], 'd': ['e'], 'e':['a']})
স্পষ্ট করা:
দৃ Conn়ভাবে সংযুক্ত উপাদানগুলি সমস্ত উপগ্রহগুলি খুঁজে পেতে পারে যার মধ্যে কমপক্ষে একটি চক্র রয়েছে, গ্রাফের সমস্ত সম্ভাব্য চক্র নয়। উদাহরণস্বরূপ, যদি আপনি সমস্ত দৃ connected়ভাবে সংযুক্ত উপাদানগুলি গ্রহণ করেন এবং ভাঙ্গা / গোষ্ঠী / সেগুলির প্রত্যেককে একটি নোডে (যেমন উপাদান অনুসারে নোড) একীভূত করেন, আপনি কোনও চক্রবিহীন একটি গাছ পাবেন (একটি ডিএজি আসলে)। প্রতিটি উপাদান (যা মূলত এটিতে কমপক্ষে একটি চক্র সহ একটি সাবগ্রাফ্ট) অভ্যন্তরীণভাবে আরও অনেকগুলি সম্ভাব্য চক্র ধারণ করতে পারে, সুতরাং এসসিসি সমস্ত সম্ভাব্য চক্রটি খুঁজে পাবে না, এটি কমপক্ষে একটি চক্রযুক্ত সমস্ত সম্ভাব্য গোষ্ঠী খুঁজে পাবে এবং আপনি যদি গ্রুপ করেন তবে তাদের, তারপরে গ্রাফের চক্র থাকবে না।
গ্রাফের সমস্ত সাধারণ চক্র খুঁজে পেতে , যেমন অন্যরা উল্লেখ করেছেন, জনসনের অ্যালগরিদম একজন প্রার্থী।
আমাকে একবার সাক্ষাত্কারের প্রশ্ন হিসাবে এটি দেওয়া হয়েছিল, আমার সন্দেহ হয় এটি আপনার সাথে ঘটেছে এবং আপনি এখানে সাহায্যের জন্য আসছেন। সমস্যাটি তিনটি প্রশ্নের মধ্যে ভাঙ্গা এবং এটি আরও সহজ হয়ে যায়।
সমস্যা 1) পুনরাবৃত্ত রুটের ফলাফলগুলির একটি উপায় সরবরাহ করতে পুনরাবৃত্তকারী প্যাটার্নটি ব্যবহার করুন। পরের রুটটি পাওয়ার জন্য যুক্তি যুক্ত করার জন্য একটি ভাল জায়গা সম্ভবত আপনার পুনরুক্তিকারীর "মুভনেক্সট"। একটি বৈধ রুট খুঁজতে, এটি আপনার ডেটা কাঠামোর উপর নির্ভর করে। আমার জন্য এটি বৈধ রুটের সম্ভাবনায় পূর্ণ একটি বর্গাকার টেবিল ছিল তাই আমাকে একটি উত্স প্রদত্ত বৈধ গন্তব্যগুলি পেতে একটি কোয়েরি তৈরি করতে হয়েছিল।
সমস্যা 2) প্রতিটি নোডকে ধাক্কা দেওয়ার সাথে সাথে আপনি যখন সেগুলি সংগ্রহ করতে পেলেন, এটির অর্থ হ'ল আপনি উড়ন্ত স্থানে যে সংগ্রহটি তৈরি করছেন তা জিজ্ঞাসাবাদ করে আপনি খুব সহজেই কোনও বিন্দুতে "দ্বিগুণ ফিরে" যাচ্ছেন কিনা তা দেখতে পাবেন।
সমস্যা 3) যদি কোনও মুহুর্তে আপনি দেখতে পান যে আপনি পিছিয়ে দ্বিগুণ হয়ে যাচ্ছেন, আপনি সংগ্রহ থেকে জিনিসগুলি পপ করতে এবং "ব্যাক আপ" রাখতে পারেন। তারপরে সেই জায়গা থেকে আবার "এগিয়ে" যাওয়ার চেষ্টা করুন।
হ্যাক: আপনি যদি এসকিএল সার্ভার ২০০৮ ব্যবহার করেন তবে কিছু নতুন "হায়ারার্কি" রয়েছে যা আপনি খুব শীঘ্রই সমাধান করতে ব্যবহার করতে পারেন যদি আপনি কোনও গাছের মধ্যে আপনার ডেটা গঠন করেন।
পিছনের প্রান্তগুলি সহ ডিএফএস-ভিত্তিক রূপগুলি প্রকৃতপক্ষে চক্রটি খুঁজে পেতে পারে তবে অনেক ক্ষেত্রে এটি ন্যূনতম হবে না চক্র নয়। সাধারণভাবে ডিএফএস আপনাকে পতাকা দেয় যে একটি চক্র রয়েছে তবে এটি চক্রটি সন্ধান করার পক্ষে যথেষ্ট ভাল নয়। উদাহরণস্বরূপ, 5 টি পৃথক চক্র দুটি প্রান্ত ভাগ করে নেওয়ার কল্পনা করুন। স্রেফ ডিএফএস (ব্যাকট্র্যাকিং ভেরিয়েন্ট সহ) ব্যবহার করে চক্র সনাক্ত করার কোনও সহজ উপায় নেই।
জনসনের অ্যালগরিদম প্রকৃতপক্ষে সমস্ত অনন্য সাধারণ চক্র দেয় এবং এতে সময় এবং স্থানের জটিলতা রয়েছে।
তবে আপনি যদি কেবলমাত্র ন্যূনতম চক্রগুলি খুঁজতে চান (এর অর্থ যে কোনও চূড়ান্ত মধ্য দিয়ে আরও একটি চক্র থাকতে পারে এবং আমরা ন্যূনতমগুলি সন্ধান করতে আগ্রহী) এবং আপনার গ্রাফটি খুব বড় নয়, আপনি নীচের সহজ পদ্ধতিটি ব্যবহার করার চেষ্টা করতে পারেন। এটি জনসনের তুলনায় খুব সহজ তবে ধীর।
সুতরাং, ন্যূনতম চক্রটি সন্ধান করার একেবারে সহজ উপায় হ'ল সংলগ্ন ম্যাট্রিক্স ব্যবহার করে সমস্ত উল্লম্বের মধ্যে ন্যূনতম পাথগুলি খুঁজে পেতে ফ্লয়েডের অ্যালগরিদম ব্যবহার করা। এই অ্যালগরিদম জনসনের মতো সর্বোত্তম কাছাকাছি কোথাও নেই, তবে এটি এত সহজ এবং এর অভ্যন্তরীণ লুপটি এতটা শক্ত যে ছোট গ্রাফের জন্য (<= 50-100 নোড) এটি ব্যবহার করা একেবারেই বুদ্ধিমান। সময়ের জটিলতা হ'ল হে (এন ^ 3), স্পেস জটিলতা হে (এন ^ 2) আপনি প্যারেন্ট ট্র্যাকিং ব্যবহার করেন এবং যদি না করেন তবে হে (1)। প্রথমে একটি চক্র থাকলে প্রশ্নের উত্তর সন্ধান করি। অ্যালগরিদম মৃত-সহজ। নীচে স্কালায় স্নিপেট রয়েছে।
val NO_EDGE = Integer.MAX_VALUE / 2
def shortestPath(weights: Array[Array[Int]]) = {
for (k <- weights.indices;
i <- weights.indices;
j <- weights.indices) {
val throughK = weights(i)(k) + weights(k)(j)
if (throughK < weights(i)(j)) {
weights(i)(j) = throughK
}
}
}
মূলত এই অ্যালগরিদমটি ভারী প্রান্তের গ্রাফটিতে সমস্ত জোড় নোডের মধ্যে সংক্ষিপ্ততম পাথগুলি খুঁজে পেতে (তাই ওজন যুক্তি) পরিচালনা করে। এটি সঠিকভাবে কাজ করার জন্য আপনাকে নোডের মধ্যে নির্দেশিত প্রান্ত বা অন্যথায় NO_EDGE থাকলে 1 টি সরবরাহ করতে হবে। অ্যালগরিদম কার্যকর করার পরে, আপনি মূল তির্যকটি পরীক্ষা করতে পারেন, যদি মানগুলি কম থাকে তবে NO_EDGE এই নোডের চেয়ে সমান দৈর্ঘ্যের চক্রে অংশ নেয়। একই চক্রের প্রতিটি অন্যান্য নোডের সমান মান হবে (মূল তিরুঙ্গে)।
চক্রটি নিজেই পুনর্গঠন করার জন্য আমাদের প্যারেন্ট ট্র্যাকিংয়ের সাথে অ্যালগরিদমের কিছুটা পরিবর্তিত সংস্করণ ব্যবহার করা দরকার।
def shortestPath(weights: Array[Array[Int]], parents: Array[Array[Int]]) = {
for (k <- weights.indices;
i <- weights.indices;
j <- weights.indices) {
val throughK = weights(i)(k) + weights(k)(j)
if (throughK < weights(i)(j)) {
parents(i)(j) = k
weights(i)(j) = throughK
}
}
}
প্রথমদিকে পিতামাতার ম্যাট্রিক্সের প্রান্ত সেলটিতে উত্সের শীর্ষস্থানীয় সূচক থাকা উচিত যদি অন্যদিকে এবং -1 এর মধ্যে একটি প্রান্ত থাকে। ফাংশন ফিরে আসার পরে, প্রতিটি প্রান্তের জন্য আপনার সবচেয়ে সংক্ষিপ্ত পথ গাছের প্যারেন্ট নোডের রেফারেন্স থাকবে। এবং তারপরে প্রকৃত চক্রগুলি পুনরুদ্ধার করা সহজ।
সব মিলিয়ে সমস্ত ন্যূনতম চক্র সন্ধান করার জন্য আমাদের নীচের প্রোগ্রাম রয়েছে
val NO_EDGE = Integer.MAX_VALUE / 2;
def shortestPathWithParentTracking(
weights: Array[Array[Int]],
parents: Array[Array[Int]]) = {
for (k <- weights.indices;
i <- weights.indices;
j <- weights.indices) {
val throughK = weights(i)(k) + weights(k)(j)
if (throughK < weights(i)(j)) {
parents(i)(j) = parents(i)(k)
weights(i)(j) = throughK
}
}
}
def recoverCycles(
cycleNodes: Seq[Int],
parents: Array[Array[Int]]): Set[Seq[Int]] = {
val res = new mutable.HashSet[Seq[Int]]()
for (node <- cycleNodes) {
var cycle = new mutable.ArrayBuffer[Int]()
cycle += node
var other = parents(node)(node)
do {
cycle += other
other = parents(other)(node)
} while(other != node)
res += cycle.sorted
}
res.toSet
}
এবং ফলাফলটি পরীক্ষা করার জন্য একটি ছোট্ট প্রধান পদ্ধতি
def main(args: Array[String]): Unit = {
val n = 3
val weights = Array(Array(NO_EDGE, 1, NO_EDGE), Array(NO_EDGE, NO_EDGE, 1), Array(1, NO_EDGE, NO_EDGE))
val parents = Array(Array(-1, 1, -1), Array(-1, -1, 2), Array(0, -1, -1))
shortestPathWithParentTracking(weights, parents)
val cycleNodes = parents.indices.filter(i => parents(i)(i) < NO_EDGE)
val cycles: Set[Seq[Int]] = recoverCycles(cycleNodes, parents)
println("The following minimal cycle found:")
cycles.foreach(c => println(c.mkString))
println(s"Total: ${cycles.size} cycle found")
}
এবং আউটপুট হয়
The following minimal cycle found:
012
Total: 1 cycle found
পুনঃনির্দেশিত গ্রাফের ক্ষেত্রে, সম্প্রতি প্রকাশিত একটি কাগজ ( অনির্দেশিত গ্রাফগুলিতে চক্র এবং স্ট-পাথের অনুকূল তালিকা ) একটি আশ্রয়হীনভাবে অনুকূল সমাধান সরবরাহ করে। আপনি এটি এখানে http://arxiv.org/abs/1205.2766 পড়তে পারেন বা এখানে http://dl.acm.org/citation.cfm?id=2627951 আমি জানি এটি আপনার প্রশ্নের উত্তর দেয় না, তবে শিরোনামের পরে আপনার প্রশ্নে দিক নির্দেশনা উল্লেখ করা হয়নি, এটি Google অনুসন্ধানের জন্য এখনও কার্যকর হতে পারে
নোড এক্স থেকে শুরু করুন এবং সমস্ত শিশু নোডের জন্য পরীক্ষা করুন (পুনঃনির্দেশিত হলে পিতামাতার এবং শিশু নোডগুলি সমান)। এই শিশু নোডগুলিকে এক্সের সন্তান হিসাবে চিহ্নিত করুন such এ জাতীয় যে কোনও শিশু নোড থেকে এটি এ, এক্স 'এর সন্তান হওয়ার চিহ্ন চিহ্নিত করুন, যেখানে এক্স' কে 2 ধাপ দূরে চিহ্নিত করা হয়েছে))। যদি আপনি পরে এক্সকে আঘাত করেন এবং এটিকে X '' এর শিশু হিসাবে চিহ্নিত করেন, তার অর্থ X একটি 3 নোড চক্রের মধ্যে রয়েছে। এর পিতামাতাকে ব্যাকট্র্যাকিং করা সহজ (যেমনটি, অ্যালগরিদমের কোনও সমর্থন নেই তাই আপনি যে কোনও পিতামাতার এক্স 'রয়েছে তা খুঁজে পেতে পারেন)।
দ্রষ্টব্য: যদি গ্রাফটি পুনঃনির্দেশিত হয় বা কোনও দ্বিদ্বিদী প্রান্তগুলি থাকে তবে এই অ্যালগরিদম আরও জটিল হয়ে যায়, ধরে নিয়ে আপনি একই চক্রের জন্য দু'বার একই প্রান্তটি অতিক্রম করতে চান না।
আপনি যা চান তা যদি গ্রাফের সমস্ত প্রাথমিক সার্কিটগুলি সন্ধান করতে হয় তবে আপনি ১৯AME০ সাল থেকে একটি কাগজে পাওয়া যায় জেমস সি টিয়ার্নান দ্বারা ইসি অ্যালগরিদম ব্যবহার করতে পারেন।
খুব আসল ইসি অ্যালগরিদম হিসাবে আমি পিএইচপি এটি বাস্তবায়ন করতে পরিচালিত (আশা কোন ভুল হয় নিচে দেখানো)। এটি যদি থাকে তবে এটি লুপগুলিও সন্ধান করতে পারে। এই বাস্তবায়নের সার্কিটগুলি (যেটি মূল ক্লোন করার চেষ্টা করে) হ'ল শূন্য উপাদান। শূন্য এখানে অস্তিত্ব জন্য (আমরা এটি জানি নাল)।
এগুলি ছাড়াও নীচে অন্য বাস্তবায়ন অনুসরণ করে যা অ্যালগোরিদমকে আরও স্বতন্ত্রতা দেয়, এর অর্থ নোডগুলি কোথাও থেকে এমনকি নেতিবাচক সংখ্যাগুলি থেকে শুরু করতে পারে, যেমন -4, -3, -2, .. ইত্যাদি from
উভয় ক্ষেত্রে নোডগুলি ক্রমযুক্ত হওয়া প্রয়োজন।
আপনার মূল কাগজ জেমস সি। টিয়ারান প্রাথমিক এলার্জি সার্কিট অ্যালগরিদম অধ্যয়ন করতে হবে
<?php
echo "<pre><br><br>";
$G = array(
1=>array(1,2,3),
2=>array(1,2,3),
3=>array(1,2,3)
);
define('N',key(array_slice($G, -1, 1, true)));
$P = array(1=>0,2=>0,3=>0,4=>0,5=>0);
$H = array(1=>$P, 2=>$P, 3=>$P, 4=>$P, 5=>$P );
$k = 1;
$P[$k] = key($G);
$Circ = array();
#[Path Extension]
EC2_Path_Extension:
foreach($G[$P[$k]] as $j => $child ){
if( $child>$P[1] and in_array($child, $P)===false and in_array($child, $H[$P[$k]])===false ){
$k++;
$P[$k] = $child;
goto EC2_Path_Extension;
} }
#[EC3 Circuit Confirmation]
if( in_array($P[1], $G[$P[$k]])===true ){//if PATH[1] is not child of PATH[current] then don't have a cycle
$Circ[] = $P;
}
#[EC4 Vertex Closure]
if($k===1){
goto EC5_Advance_Initial_Vertex;
}
//afou den ksana theoreitai einai asfales na svisoume
for( $m=1; $m<=N; $m++){//H[P[k], m] <- O, m = 1, 2, . . . , N
if( $H[$P[$k-1]][$m]===0 ){
$H[$P[$k-1]][$m]=$P[$k];
break(1);
}
}
for( $m=1; $m<=N; $m++ ){//H[P[k], m] <- O, m = 1, 2, . . . , N
$H[$P[$k]][$m]=0;
}
$P[$k]=0;
$k--;
goto EC2_Path_Extension;
#[EC5 Advance Initial Vertex]
EC5_Advance_Initial_Vertex:
if($P[1] === N){
goto EC6_Terminate;
}
$P[1]++;
$k=1;
$H=array(
1=>array(1=>0,2=>0,3=>0,4=>0,5=>0),
2=>array(1=>0,2=>0,3=>0,4=>0,5=>0),
3=>array(1=>0,2=>0,3=>0,4=>0,5=>0),
4=>array(1=>0,2=>0,3=>0,4=>0,5=>0),
5=>array(1=>0,2=>0,3=>0,4=>0,5=>0)
);
goto EC2_Path_Extension;
#[EC5 Advance Initial Vertex]
EC6_Terminate:
print_r($Circ);
?>
তারপরে এটি অন্য বাস্তবায়ন, গ্রাফের চেয়ে আরও স্বতন্ত্র, গোটো এবং অ্যারের মান ব্যতীত, পরিবর্তে এটি অ্যারে কী ব্যবহার করে, পথ, গ্রাফ এবং সার্কিটগুলি অ্যারে কী হিসাবে সংরক্ষণ করা হয় (যদি আপনি চান তবে অ্যারের মানগুলি ব্যবহার করুন, কেবল প্রয়োজনীয় পরিবর্তন করুন লাইন)। উদাহরণ স্বরূপ দেখানোর জন্য গ্রাফ -4 থেকে শুরু হয়।
<?php
$G = array(
-4=>array(-4=>true,-3=>true,-2=>true),
-3=>array(-4=>true,-3=>true,-2=>true),
-2=>array(-4=>true,-3=>true,-2=>true)
);
$C = array();
EC($G,$C);
echo "<pre>";
print_r($C);
function EC($G, &$C){
$CNST_not_closed = false; // this flag indicates no closure
$CNST_closed = true; // this flag indicates closure
// define the state where there is no closures for some node
$tmp_first_node = key($G); // first node = first key
$tmp_last_node = $tmp_first_node-1+count($G); // last node = last key
$CNST_closure_reset = array();
for($k=$tmp_first_node; $k<=$tmp_last_node; $k++){
$CNST_closure_reset[$k] = $CNST_not_closed;
}
// define the state where there is no closure for all nodes
for($k=$tmp_first_node; $k<=$tmp_last_node; $k++){
$H[$k] = $CNST_closure_reset; // Key in the closure arrays represent nodes
}
unset($tmp_first_node);
unset($tmp_last_node);
# Start algorithm
foreach($G as $init_node => $children){#[Jump to initial node set]
#[Initial Node Set]
$P = array(); // declare at starup, remove the old $init_node from path on loop
$P[$init_node]=true; // the first key in P is always the new initial node
$k=$init_node; // update the current node
// On loop H[old_init_node] is not cleared cause is never checked again
do{#Path 1,3,7,4 jump here to extend father 7
do{#Path from 1,3,8,5 became 2,4,8,5,6 jump here to extend child 6
$new_expansion = false;
foreach( $G[$k] as $child => $foo ){#Consider each child of 7 or 6
if( $child>$init_node and isset($P[$child])===false and $H[$k][$child]===$CNST_not_closed ){
$P[$child]=true; // add this child to the path
$k = $child; // update the current node
$new_expansion=true;// set the flag for expanding the child of k
break(1); // we are done, one child at a time
} } }while(($new_expansion===true));// Do while a new child has been added to the path
# If the first node is child of the last we have a circuit
if( isset($G[$k][$init_node])===true ){
$C[] = $P; // Leaving this out of closure will catch loops to
}
# Closure
if($k>$init_node){ //if k>init_node then alwaya count(P)>1, so proceed to closure
$new_expansion=true; // $new_expansion is never true, set true to expand father of k
unset($P[$k]); // remove k from path
end($P); $k_father = key($P); // get father of k
$H[$k_father][$k]=$CNST_closed; // mark k as closed
$H[$k] = $CNST_closure_reset; // reset k closure
$k = $k_father; // update k
} } while($new_expansion===true);//if we don't wnter the if block m has the old k$k_father_old = $k;
// Advance Initial Vertex Context
}//foreach initial
}//function
?>
আমি ইসিকে বিশ্লেষণ করে নথিভুক্ত করেছি তবে দুর্ভাগ্যক্রমে ডকুমেন্টেশনটি গ্রীক ভাষায় রয়েছে।
একটি ড্যাজে সমস্ত চক্র সন্ধানের জন্য দুটি পদক্ষেপ (অ্যালগোরিদম) জড়িত।
প্রথম পদক্ষেপটি হ'ল দৃjan়ভাবে সংযুক্ত উপাদানগুলির সেট খুঁজতে টার্জনের অ্যালগরিদম ব্যবহার করা।
দ্বিতীয় পদক্ষেপটি সংযুক্ত উপাদানগুলির মধ্যে চক্র (পাথ) সন্ধান করা। আমার পরামর্শ হায়ারহোলজারের অ্যালগরিদমের একটি পরিবর্তিত সংস্করণ ব্যবহার করা।
ধারণাটি হ'ল:
এখানে একটি পরীক্ষার কেস সহ জাভা প্রয়োগের লিঙ্কটি রয়েছে:
http://stones333.blogspot.com/2013/12/find-cycles-in-directed-graph-dag.html
আমি নিম্নলিখিত অ্যালগরিদমকে হোঁচট খেয়েছি যা জনসনের অ্যালগরিদমের চেয়ে কমপক্ষে কার্যকর বলে মনে হচ্ছে (কমপক্ষে আরও বড় গ্রাফের জন্য)। টারজানের অ্যালগরিদমের তুলনায় আমি এর অভিনয় সম্পর্কে নিশ্চিত নই।
অতিরিক্তভাবে, আমি এটিকে এখনও কেবল ত্রিভুজগুলির জন্য পরীক্ষা করে দেখেছি। আগ্রহী হলে দয়া করে নরিশিগ চিবা এবং টাকানো নিশিজেকি ( http://dx.doi.org/10.1137/0214017 ) "অর্বোরিসিটি এবং সাবগ্রাফার তালিকাভুক্তকরণ অ্যালগরিদম" দেখুন
জাভাস্ক্রিপ্ট সমাধান বিচ্ছিন্নভাবে লিঙ্কযুক্ত তালিকা ব্যবহার করে। দ্রুত রান সময়ের জন্য সেট অরণ্যগুলিকে ছত্রভঙ্গ করতে আপগ্রেড করা যেতে পারে।
var input = '5\nYYNNN\nYYYNN\nNYYNN\nNNNYN\nNNNNY'
console.log(input);
//above solution should be 3 because the components are
//{0,1,2}, because {0,1} and {1,2} therefore {0,1,2}
//{3}
//{4}
//MIT license, authored by Ling Qing Meng
//'4\nYYNN\nYYYN\nNYYN\nNNNY'
//Read Input, preformatting
var reformat = input.split(/\n/);
var N = reformat[0];
var adjMatrix = [];
for (var i = 1; i < reformat.length; i++) {
adjMatrix.push(reformat[i]);
}
//for (each person x from 1 to N) CREATE-SET(x)
var sets = [];
for (var i = 0; i < N; i++) {
var s = new LinkedList();
s.add(i);
sets.push(s);
}
//populate friend potentials using combinatorics, then filters
var people = [];
var friends = [];
for (var i = 0; i < N; i++) {
people.push(i);
}
var potentialFriends = k_combinations(people,2);
for (var i = 0; i < potentialFriends.length; i++){
if (isFriend(adjMatrix,potentialFriends[i]) === 'Y'){
friends.push(potentialFriends[i]);
}
}
//for (each pair of friends (x y) ) if (FIND-SET(x) != FIND-SET(y)) MERGE-SETS(x, y)
for (var i = 0; i < friends.length; i++) {
var x = friends[i][0];
var y = friends[i][1];
if (FindSet(x) != FindSet(y)) {
sets.push(MergeSet(x,y));
}
}
for (var i = 0; i < sets.length; i++) {
//sets[i].traverse();
}
console.log('How many distinct connected components?',sets.length);
//Linked List data structures neccesary for above to work
function Node(){
this.data = null;
this.next = null;
}
function LinkedList(){
this.head = null;
this.tail = null;
this.size = 0;
// Add node to the end
this.add = function(data){
var node = new Node();
node.data = data;
if (this.head == null){
this.head = node;
this.tail = node;
} else {
this.tail.next = node;
this.tail = node;
}
this.size++;
};
this.contains = function(data) {
if (this.head.data === data)
return this;
var next = this.head.next;
while (next !== null) {
if (next.data === data) {
return this;
}
next = next.next;
}
return null;
};
this.traverse = function() {
var current = this.head;
var toPrint = '';
while (current !== null) {
//callback.call(this, current); put callback as an argument to top function
toPrint += current.data.toString() + ' ';
current = current.next;
}
console.log('list data: ',toPrint);
}
this.merge = function(list) {
var current = this.head;
var next = current.next;
while (next !== null) {
current = next;
next = next.next;
}
current.next = list.head;
this.size += list.size;
return this;
};
this.reverse = function() {
if (this.head == null)
return;
if (this.head.next == null)
return;
var currentNode = this.head;
var nextNode = this.head.next;
var prevNode = this.head;
this.head.next = null;
while (nextNode != null) {
currentNode = nextNode;
nextNode = currentNode.next;
currentNode.next = prevNode;
prevNode = currentNode;
}
this.head = currentNode;
return this;
}
}
/**
* GENERAL HELPER FUNCTIONS
*/
function FindSet(x) {
for (var i = 0; i < sets.length; i++){
if (sets[i].contains(x) != null) {
return sets[i].contains(x);
}
}
return null;
}
function MergeSet(x,y) {
var listA,listB;
for (var i = 0; i < sets.length; i++){
if (sets[i].contains(x) != null) {
listA = sets[i].contains(x);
sets.splice(i,1);
}
}
for (var i = 0; i < sets.length; i++) {
if (sets[i].contains(y) != null) {
listB = sets[i].contains(y);
sets.splice(i,1);
}
}
var res = MergeLists(listA,listB);
return res;
}
function MergeLists(listA, listB) {
var listC = new LinkedList();
listA.merge(listB);
listC = listA;
return listC;
}
//access matrix by i,j -> returns 'Y' or 'N'
function isFriend(matrix, pair){
return matrix[pair[0]].charAt(pair[1]);
}
function k_combinations(set, k) {
var i, j, combs, head, tailcombs;
if (k > set.length || k <= 0) {
return [];
}
if (k == set.length) {
return [set];
}
if (k == 1) {
combs = [];
for (i = 0; i < set.length; i++) {
combs.push([set[i]]);
}
return combs;
}
// Assert {1 < k < set.length}
combs = [];
for (i = 0; i < set.length - k + 1; i++) {
head = set.slice(i, i+1);
tailcombs = k_combinations(set.slice(i + 1), k - 1);
for (j = 0; j < tailcombs.length; j++) {
combs.push(head.concat(tailcombs[j]));
}
}
return combs;
}
প্রারম্ভ নোড গুলি থেকে ডিএফএস, ট্র্যাভারসাল চলাকালীন ডিএফএস পাথের উপর নজর রাখুন, এবং যদি আপনি নোড ভি থেকে স এর পথে কোনও প্রান্ত খুঁজে পান তবে পাথটি রেকর্ড করুন। (v, s) হ'ল ডিএফএস গাছের পিছনের দিক এবং এটি একটি চক্রকে বোঝায় s
পারমিটেশন চক্র সম্পর্কে আপনার প্রশ্ন সম্পর্কে , এখানে আরও পড়ুন: https://www.codechef.com/problems/PCYCLE
আপনি এই কোডটি চেষ্টা করতে পারেন (আকার এবং অঙ্ক সংখ্যা লিখুন):
# include<cstdio>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int num[1000];
int visited[1000]={0};
int vindex[2000];
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
int t_visited=0;
int cycles=0;
int start=0, index;
while(t_visited < n)
{
for(int i=1;i<=n;i++)
{
if(visited[i]==0)
{
vindex[start]=i;
visited[i]=1;
t_visited++;
index=start;
break;
}
}
while(true)
{
index++;
vindex[index]=num[vindex[index-1]];
if(vindex[index]==vindex[start])
break;
visited[vindex[index]]=1;
t_visited++;
}
vindex[++index]=0;
start=index+1;
cycles++;
}
printf("%d\n",cycles,vindex[0]);
for(int i=0;i<(n+2*cycles);i++)
{
if(vindex[i]==0)
printf("\n");
else
printf("%d ",vindex[i]);
}
}
দ্বিতীয় তলের উত্তরের সিউডো-কোডের জন্য ডিএফএস সি ++ সংস্করণ:
void findCircleUnit(int start, int v, bool* visited, vector<int>& path) {
if(visited[v]) {
if(v == start) {
for(auto c : path)
cout << c << " ";
cout << endl;
return;
}
else
return;
}
visited[v] = true;
path.push_back(v);
for(auto i : G[v])
findCircleUnit(start, i, visited, path);
visited[v] = false;
path.pop_back();
}