কীভাবে ডিজকস্ট্রার অ্যালগোরিদম এবং এ-স্টার তুলনা করে?


154

আমি দেখছিলাম মারিও এআই প্রতিযোগিতার ছেলেরা কী করছে এবং তাদের মধ্যে কেউ এ * (এ-স্টার) পাথিং অ্যালগরিদমকে ব্যবহার করে কিছু সুন্দর ঝরঝরে মারিও বট তৈরি করেছে।

বিকল্প পাঠ
( মারিও এ এর ​​একটি ভিডিও * বট ইন অ্যাকশন )

আমার প্রশ্ন, এ-স্টার কীভাবে ডিজকস্ট্রার সাথে তুলনা করে? তাদের দিকে তাকিয়ে, তারা একই মনে হয়।

কেউ কেন একে অপরকে ব্যবহার করবে? বিশেষ করে গেমসে পথ চলার প্রসঙ্গে?



@ এসলাকস এ * ডিজকস্ট্রার চেয়ে বেশি মেমরি ব্যবহার করে? ডাইজকস্ট্রা তাদের সমস্ত চেষ্টা করার সময় যদি কোনও * পথের প্রতিশ্রুতিযুক্ত নোডগুলি কীভাবে আসে?
পোট্রাথোর

উত্তর:


177

ডিজকস্ট্রা হ'ল এ * এর জন্য একটি বিশেষ কেস (যখন হিউরিস্টিক্স শূন্য হয়)।


1
ডিজকস্ট্রে আমরা কেবল উত্স থেকে দূরত্বকেই সঠিক বিবেচনা করি? এবং সর্বনিম্ন ভারটেক্স বিবেচনায় নেওয়া হয়?
ক্রাকেন

4
আমি ভেবেছিলাম A * ডিজকস্ট্রার জন্য একটি বিশেষ ঘটনা যেখানে তারা হিউরিস্টিক ব্যবহার করে। যেহেতু ডিজকસ્ત્ર সেখানে প্রথম আফাইক ছিলেন।
ম্যাডমিনিয়ো

46
@ মেন্নোগউ: হ্যাঁ ডিজকস্ট্রার অ্যালগরিদমটি প্রথমে তৈরি হয়েছিল; তবে এটি আরও সাধারণ অ্যালগরিদম এ * এর একটি বিশেষ ক্ষেত্রে। প্রথমে বিশেষ ক্ষেত্রে সন্ধান করা এবং পরে সাধারণীকরণ করা মোটেই অস্বাভাবিক নয় (বাস্তবে সম্ভবত আদর্শ))
পিটার জেরকেনস

1
হিউরিস্টিকস জানেন এমন যে কেউ জন্য দুর্দান্ত উত্তর;)
lindhe

1
এ * এবং হিউরিস্টিক্সের ব্যবহার নরভিগ এবং রাসেলের এআই বইতে
বল্টজম্যানব্রেন

113

Dijkstra:

এটা এক খরচ ফাংশন, যা প্রতিটি নোডের উৎস থেকে বাস্তব খরচ মান রয়েছে: f(x)=g(x)
এটি কেবল আসল ব্যয় বিবেচনা করে উত্স থেকে প্রতিটি অন্যান্য নোডের সংক্ষিপ্ততম পথটি আবিষ্কার করে।

একটি * অনুসন্ধান:

এটির দুটি ব্যয়ের কাজ রয়েছে।

  1. g(x): ডিজকস্ট্রার মতোই। কোনও নোডে পৌঁছানোর আসল ব্যয় x
  2. h(x): নোড xথেকে লক্ষ্য নোডের আনুমানিক ব্যয় । এটি একটি হিউরিস্টিক ফাংশন। এই হিউরিস্টিক ফাংশনটি কখনই ব্যয়কে অত্যধিক বিবেচনা করে না। তার অর্থ, নোড থেকে লক্ষ্য নোডে পৌঁছানোর আসল ব্যয়টি xবৃহত্তর বা সমান হওয়া উচিত h(x)। একে বলা হয় স্বীকৃত হিউরিস্টিক।

প্রতিটি নোডের মোট ব্যয় গণনা করা হয় f(x)=g(x)+h(x)

একটি * অনুসন্ধান কেবল কোনও নোডকে প্রসারিত করে যদি এটি আশাপূর্ণ মনে হয়। এটি কেবলমাত্র বর্তমান নোড থেকে লক্ষ্য নোডে পৌঁছানোর দিকে মনোনিবেশ করে, প্রতিটি অন্যান্য নোডে পৌঁছায় না। এটি সর্বোত্তম, যদি হিউরিস্টিক ফাংশনটি গ্রহণযোগ্য হয়।

সুতরাং যদি আপনার হিরিস্টিক ফাংশনটি ভবিষ্যতের ব্যয়ের আনুমানিকভাবে ভাল হয়, তবে আপনাকে ডিজকস্ট্রার থেকে অনেক কম নোডের অন্বেষণ করতে হবে।


20

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


17
যদি বেশ কয়েকটি সম্ভাব্য লক্ষ্য নোড থাকে তবে এগুলি সমস্তগুলিকে অন্তর্ভুক্ত করার জন্য কেউ কেবল গোল টেস্টিং ফাংশনটি পরিবর্তন করতে পারে। এইভাবে, এ * একবার চালানো দরকার।
ব্র্যাড লারসন

9

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


5
কেন ডিজকস্ট্রার কখনও প্যাথফাইন্ডিংয়ের জন্য ব্যবহার করা হবে না? তুমি কি বিস্তারিত বলতে পারো?
কিংস্টেস্টার

2
কারণ এমনকি যদি আপনি একটি লম্পট হিউরিস্টিক নিয়ে আসতে পারেন তবে আপনি ডিজকস্ট্রার থেকে আরও ভাল করবেন। কখনও কখনও এটি অগ্রহণযোগ্য হলেও। এটি ডোমেনের উপর নির্ভর করে। ডিজকস্ট্রা স্বল্প-স্মৃতি পরিস্থিতিতেও কাজ করবে না, যেখানে আইডিএ * করবে।
শেগি ব্যাঙ

আমি এখানে স্লাইডগুলি পেয়েছি: webdocs.cs.ualberta.ca/~jonathan/PREVIOUS/Courses/657/Notes/…
ডেভিডটবার্নাল

7

ডিজকস্ট্রা এ * এর জন্য একটি বিশেষ কেস।

ডিজকস্ট্রা নোড থেকে শুরু করে অন্য সকলের জন্য সর্বনিম্ন ব্যয় খুঁজে পায়। একটি * শুরু নোড থেকে লক্ষ্য নোডের সর্বনিম্ন ব্যয় খুঁজে পায়।

ডিজকস্ট্রার অ্যালগরিদমটি কখনই পাথ সন্ধানের জন্য ব্যবহার করা হত না। এ * ব্যবহার করে একটি শালীন হিউরিস্টিক উপস্থিত হতে পারে। অনুসন্ধানের জায়গার উপর নির্ভর করে পুনরাবৃত্তির A * পছন্দনীয় কারণ এটি কম স্মৃতি ব্যবহার করে।

ডিজকস্ট্রার অ্যালগরিদমের কোডটি হ'ল:

// A C / C++ program for Dijkstra's single source shortest path algorithm.
// The program is for adjacency matrix representation of the graph

#include <stdio.h>
#include <limits.h>

// Number of vertices in the graph
#define V 9

// A utility function to find the vertex with minimum distance value, from
// the set of vertices not yet included in shortest path tree
int minDistance(int dist[], bool sptSet[])
{
 // Initialize min value
 int min = INT_MAX, min_index;

  for (int v = 0; v < V; v++)
   if (sptSet[v] == false && dist[v] <= min)
     min = dist[v], min_index = v;

   return min_index;
}

 int printSolution(int dist[], int n)
 {
  printf("Vertex   Distance from Source\n");
  for (int i = 0; i < V; i++)
     printf("%d \t\t %d\n", i, dist[i]);
  }

void dijkstra(int graph[V][V], int src)
{
 int dist[V];     // The output array.  dist[i] will hold the shortest
                  // distance from src to i

 bool sptSet[V]; // sptSet[i] will true if vertex i is included in shortest
                 // path tree or shortest distance from src to i is finalized

 // Initialize all distances as INFINITE and stpSet[] as false
 for (int i = 0; i < V; i++)
    dist[i] = INT_MAX, sptSet[i] = false;

 // Distance of source vertex from itself is always 0
 dist[src] = 0;

 // Find shortest path for all vertices
 for (int count = 0; count < V-1; count++)
 {
   // Pick the minimum distance vertex from the set of vertices not
   // yet processed. u is always equal to src in first iteration.
   int u = minDistance(dist, sptSet);

   // Mark the picked vertex as processed
   sptSet[u] = true;

   // Update dist value of the adjacent vertices of the picked vertex.
   for (int v = 0; v < V; v++)

     // Update dist[v] only if is not in sptSet, there is an edge from 
     // u to v, and total weight of path from src to  v through u is 
     // smaller than current value of dist[v]
     if (!sptSet[v] && graph[u][v] && dist[u] != INT_MAX 
                                   && dist[u]+graph[u][v] < dist[v])
        dist[v] = dist[u] + graph[u][v];
 }

 // print the constructed distance array
 printSolution(dist, V);
 }

// driver program to test above function
int main()
 {
 /* Let us create the example graph discussed above */
 int graph[V][V] = {{0, 4, 0, 0, 0, 0, 0, 8, 0},
                  {4, 0, 8, 0, 0, 0, 0, 11, 0},
                  {0, 8, 0, 7, 0, 4, 0, 0, 2},
                  {0, 0, 7, 0, 9, 14, 0, 0, 0},
                  {0, 0, 0, 9, 0, 10, 0, 0, 0},
                  {0, 0, 4, 14, 10, 0, 2, 0, 0},
                  {0, 0, 0, 0, 0, 2, 0, 1, 6},
                  {8, 11, 0, 0, 0, 0, 1, 0, 7},
                  {0, 0, 2, 0, 0, 0, 6, 7, 0}
                 };

dijkstra(graph, 0);

return 0;
}

এ * অ্যালগোরিদমের কোডটি হ'ল:

class Node:
def __init__(self,value,point):
    self.value = value
    self.point = point
    self.parent = None
    self.H = 0
    self.G = 0
def move_cost(self,other):
    return 0 if self.value == '.' else 1

def children(point,grid):
x,y = point.point
links = [grid[d[0]][d[1]] for d in [(x-1, y),(x,y - 1),(x,y + 1),(x+1,y)]]
return [link for link in links if link.value != '%']
def manhattan(point,point2):
return abs(point.point[0] - point2.point[0]) + abs(point.point[1]-point2.point[0])
def aStar(start, goal, grid):
#The open and closed sets
openset = set()
closedset = set()
#Current point is the starting point
current = start
#Add the starting point to the open set
openset.add(current)
#While the open set is not empty
while openset:
    #Find the item in the open set with the lowest G + H score
    current = min(openset, key=lambda o:o.G + o.H)
    #If it is the item we want, retrace the path and return it
    if current == goal:
        path = []
        while current.parent:
            path.append(current)
            current = current.parent
        path.append(current)
        return path[::-1]
    #Remove the item from the open set
    openset.remove(current)
    #Add it to the closed set
    closedset.add(current)
    #Loop through the node's children/siblings
    for node in children(current,grid):
        #If it is already in the closed set, skip it
        if node in closedset:
            continue
        #Otherwise if it is already in the open set
        if node in openset:
            #Check if we beat the G score 
            new_g = current.G + current.move_cost(node)
            if node.G > new_g:
                #If so, update the node to have a new parent
                node.G = new_g
                node.parent = current
        else:
            #If it isn't in the open set, calculate the G and H score for the node
            node.G = current.G + current.move_cost(node)
            node.H = manhattan(node, goal)
            #Set the parent to our current item
            node.parent = current
            #Add it to the set
            openset.add(node)
    #Throw an exception if there is no path
    raise ValueError('No Path Found')
def next_move(pacman,food,grid):
#Convert all the points to instances of Node
for x in xrange(len(grid)):
    for y in xrange(len(grid[x])):
        grid[x][y] = Node(grid[x][y],(x,y))
#Get the path
path = aStar(grid[pacman[0]][pacman[1]],grid[food[0]][food[1]],grid)
#Output the path
print len(path) - 1
for node in path:
    x, y = node.point
    print x, y
pacman_x, pacman_y = [ int(i) for i in raw_input().strip().split() ]
food_x, food_y = [ int(i) for i in raw_input().strip().split() ]
x,y = [ int(i) for i in raw_input().strip().split() ]

grid = []
for i in xrange(0, x):
grid.append(list(raw_input().strip()))

next_move((pacman_x, pacman_y),(food_x, food_y), grid)

বন্ধ হওয়া প্রতিবেশী যা ইতিমধ্যে বদ্ধ সেটে রয়েছে সাবঅস্টিমাল দেবে। এই গ্রাফটিতে এটি চেষ্টা করা (এটি একটি ইউটিউব ভিডিও উদাহরণ, ভাষাটিকে উপেক্ষা করুন) ভুল উত্তর দেবে।
ইটজওয়ালা

5

ডিজকস্ট্রা নোড থেকে শুরু করে অন্য সকলের জন্য সর্বনিম্ন ব্যয় খুঁজে পায়। একটি * শুরু নোড থেকে লক্ষ্য নোডের সর্বনিম্ন ব্যয় খুঁজে পায়।

সুতরাং মনে হচ্ছে ডিজকસ્ત્રা কম দক্ষ হবে যখন আপনার প্রয়োজন সমস্ত এক নোড থেকে অন্য নোডের ন্যূনতম দূরত্ব।


2
এটি সত্য নয়। স্ট্যান্ডার্ড ডিজকস্ট্রা দুটি পয়েন্টের মধ্যে সংক্ষিপ্ততম পথ দিতে ব্যবহৃত হয়।
এমিল

3
দয়া করে বিভ্রান্ত করবেন না, ডিজকস্ট্রা এর ফলাফলগুলি অন্য সমস্ত শীর্ষে দিয়ে দেয়। সুতরাং এটি ধীর কাজ করে।
ইভান ভোরোশিলিন

আমি দ্বিতীয় ইমেল মন্তব্য। আপনাকে যা করতে হবে তা হল অগ্রাধিকারের সারি থেকে গন্তব্য নোডটি সরিয়ে দেওয়ার সময় থামানো এবং আপনার উত্স থেকে গন্তব্য পর্যন্ত সবচেয়ে কম পথ। এটি আসলে আসল অ্যালগরিদম ছিল।
seteropere

আরও সুনির্দিষ্টভাবে: যদি কোনও লক্ষ্য নির্দিষ্ট করা হয়, তবে নির্দিষ্ট লক্ষ্যমাত্রার পথের চেয়ে ছোট পাথের উপর অবস্থিত সমস্ত নোডের নিকটতম দিকটি ডিজকস্ট্রা সন্ধান করে। এ * এর হিউরিস্টিকের উদ্দেশ্য হ'ল এই কয়েকটি পথকে ছাঁটাই করা। হিউরিস্টিকের কার্যকারিতা নির্ধারণ করে যে কতজন ছাঁটাই হয়েছে।
ওয়েলন ফ্লিন 13

@ সেটারোপেয়ার, তবে যদি আপনার গন্তব্য নোডটি অনুসন্ধান করা হয় তবে সর্বশেষ নোডটি কী হবে? এটি অবশ্যই কম দক্ষ, কারণ এ * এর হিউরিস্টিক্স এবং অগ্রাধিকার নোডগুলি বেছে নেওয়া গন্তব্য নোডের তালিকার শেষ নোড নয় তা নিশ্চিত করতে সহায়তা করে
নাইট0ফ্রেডাগন

5

আপনি ডিজকস্ট্রার একটি * নির্দেশিত সংস্করণ বিবেচনা করতে পারেন। অর্থ, সমস্ত নোড অন্বেষণের পরিবর্তে, আপনি কোনও দিক বাছাই করার জন্য একটি হিউরিস্টিক ব্যবহার করবেন।

এটিকে আরও দৃly়তার সাথে বলতে গেলে, আপনি যদি অগ্রাধিকারের সারি দিয়ে অ্যালগরিদমগুলি বাস্তবায়ন করেন তবে আপনি যে নোডটি ঘুরে দেখছেন তার অগ্রাধিকার ব্যয় হবে (পূর্ববর্তী নোডের দাম + এখানে আসার জন্য ব্যয়) এবং এখান থেকে তাত্ত্বিক অনুমান লক্ষ্য। ডিজকস্ট্রে থাকাকালীন অগ্রাধিকারটি কেবল নোডের আসল ব্যয়ের দ্বারা প্রভাবিত হয়। উভয় ক্ষেত্রেই, স্টপ মাপদণ্ডটি লক্ষ্যে পৌঁছে যাচ্ছে।


2

ডিজকস্ট্রার অ্যালগরিদম অবশ্যই সবচেয়ে সংক্ষিপ্ততম পথটি আবিষ্কার করে। অন্যদিকে এ * হিউরিস্টিকের উপর নির্ভর করে। এই কারণে এ * ডিজকস্ট্রার অ্যালগরিদমের চেয়ে দ্রুত এবং আপনার যদি ভাল হিউরিস্টিক হয় তবে ভাল ফলাফল দেবে।


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

4
হিউরিস্টিক যখন স্বীকৃত হয় (সর্বদা অবমূল্যায়ন করা হয়) তখন একটি * সবচেয়ে সংক্ষিপ্ত পথ দেওয়ার গ্যারান্টিযুক্ত হয়
রবার্ট

1

যদি আপনি আস্তারের জন্য স্যুইচোডকোডটি দেখেন :

foreach y in neighbor_nodes(x)
             if y in closedset
                 continue

অন্যদিকে, আপনি যদি ডিজকস্ট্রার জন্য একই জিনিসটি দেখেন :

for each neighbor v of u:         
             alt := dist[u] + dist_between(u, v) ;

সুতরাং, মুল বক্তব্যটি হ'ল আষ্টার কোনও নোডকে একাধিকবার মূল্যায়ন করবেন না,
কারণ এটি বিশ্বাস করে যে একবার নোডের দিকে তাকানোই যথেষ্ট,
তার তাত্ত্বিকতার কারণে ।

OTOH, Dijkstra এর অ্যালগরিদম নিজেকে সংশোধন করতে লজ্জাজনক নয়, যদি
কোনও নোড আবার পপ আপ হয়।

কোনটি উচিত Astar দ্রুত এবং আরো পথ খোঁজার জন্য উপযুক্ত করা।


7
এটি সত্য নয়: এ * একাধিকবার নোডগুলি দেখতে পারে। আসলে, ডিজকস্ট্র হ'ল এ * ...
এমিল

2
: শোধন জন্য এই এক চেক করুন stackoverflow.com/questions/21441662/...
spiralmoon

সমস্ত অনুসন্ধান অ্যালগরিদমের একটি "সীমান্ত" এবং একটি "পরিদর্শন করা সেট" রয়েছে। কোনও অ্যালগোরিদম কোনও দর্শনার্থী সেটে একবার নোডের পাথকে সংশোধন করে না: নকশা অনুসারে, তারা অগ্রাধিকার ক্রমে নোডগুলি সীমান্ত থেকে পরিদর্শন করা গোছায় স্থানান্তর করে। নোডের ন্যূনতম জানা দূরত্বগুলি কেবলমাত্র সীমান্তে থাকলেই আপডেট করা যায়। ডিজকস্ট্রার সেরা-প্রথম অনুসন্ধানের একটি ফর্ম, এবং কোনও নোড এটি "ভিজিট করা" সেটটিতে রাখার পরে কখনও পুনর্বিবেচনা করতে পারে না। এ * এই সম্পত্তি ভাগ করে নেয় এবং এটি সীমান্তে কোন নোডগুলি অগ্রাধিকার দেয় তা চয়ন করতে একটি সহায়ক অনুমানক ব্যবহার করে। en.wikipedia.org/wiki/Dijkstra%27s_algorithm
pygosceles

0

এ * তে, প্রতিটি নোডের জন্য আপনি তার বহির্গামী সংযোগগুলি পরীক্ষা করে দেখুন।
প্রতিটি নতুন নোডের জন্য আপনি এখন পর্যন্ত সর্বনিম্ন ব্যয় (সিএসএফ) গণনা করুন এই নোডের সংযোগের ওজন এবং আপনাকে আগের নোডে পৌঁছাতে হবে এমন ব্যয়ের উপর নির্ভর করে।
অতিরিক্তভাবে আপনি নতুন নোড থেকে লক্ষ্য নোডের জন্য ব্যয়টি অনুমান করেন এবং এটিকে সিএসএফে যুক্ত করুন। আপনার এখন আনুমানিক মোট ব্যয় (ইত্যাদি)। (ইত্যাদি = লক্ষ্যমাত্রার জন্য সিএসএফ + আনুমানিক দূরত্ব) এর পরে আপনি নতুন নোডগুলি থেকে সবচেয়ে নিম্নতমটি বেছে নিন the
আগের মতো একই কাজ করুন যতক্ষণ না কোনও নতুন নোডের লক্ষ্য না হয়।

ডিজকস্ট্র প্রায় একই রকম কাজ করে। লক্ষ্যমাত্রার আনুমানিক দূরত্বটি সর্বদা 0 হয় বাদে এবং লক্ষ্যটি কেবল নতুন নোডগুলির মধ্যে একটি নয়, তবে সর্বনিম্ন সিএসএফ সহ একটিও থাকে তবে অ্যালগরিদম প্রথম থামে ।

এ * সাধারণত ডায়স্ট্র্রার চেয়ে দ্রুত হয় যদিও এটি সবসময় হয় না। ভিডিও গেমগুলিতে আপনি প্রায়শই "গেমের জন্য যথেষ্ট পর্যাপ্ত" পদ্ধতির পছন্দ করেন। সুতরাং এ * থেকে "যথেষ্ট পর্যাপ্ত" সর্বোত্তম পথটি সাধারণত পর্যাপ্ত থাকে।


-1

Dijkstra এর অ্যালগরিদম স্পষ্টভাবে সম্পূর্ণ এবং অনুকূল যে আপনি সর্বদা সংক্ষিপ্ততম পথ পাবেন। তবে এটি মূলত একাধিক গোল নোডগুলি সনাক্ত করতে ব্যবহৃত হওয়ার কারণে এটি আরও বেশি সময় নেয়।

A* searchঅন্যদিকে তাত্ত্বিক মানগুলির সাথে গুরুত্বপূর্ণ, যা আপনি আপনার লক্ষ্য নিকটে পৌঁছানোর জন্য সংজ্ঞা দিতে পারেন, যেমন লক্ষ্যের দিকে ম্যানহাটনের দূরত্ব। এটি সর্বোত্তম বা সম্পূর্ণ হতে পারে যা Heuristic কারণের উপর নির্ভর করে। আপনার একক গোল নোড থাকলে এটি অবশ্যই দ্রুততর faster

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.