这个问题在一次采访中被问到,我仍在寻找最佳解决方案。
你有一个N细胞的迷宫。每个单元格可以有多个入口点但不超过一个出口 (即进入/退出点是像阀门一样的单向门)。
使用0的整数值命名单元格 到N-1。
您需要找到迷宫中最大周期的长度。如果没有循环则返回-1。
输入格式
输出格式
示例输入:
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
示例输出
6
我已经尝试使用DFS执行此操作以查找所有可能的周期并打印最大周期大小。 如果有更好的解决方案,请告诉我。
答案 0 :(得分:5)
给定图中的节点,从它开始有一个唯一的最大路径(因为任何节点最多只有一个出口)。它可能会也可能不会循环。
从节点开始很容易找到最终的循环长度:保持跟随退出节点,沿路径记录集合中的节点。如果找不到退出节点,或者您要访问以前访问过的节点,请停止。如果没有出口节点则没有循环,否则您可以通过从先前访问过的节点开始找到循环长度,并重新跟踪循环。 [你也可以在这里使用Floyd的算法,这需要O(1)而不是O(N)存储,但我们将在下一步中使用O(N)存储。]
使用它,可以在O(N)时间内找到最大循环:对图中的每个节点重复上述算法,但是缓存结果(如果没有找到循环,则存储-1)。如果在路径中找到先前缓存的结果,则必须小心停止上面的循环查找,并且一旦找到节点的结果,就必须缓存路径中所有节点的结果,直到找到节点的结果已经缓存。最大周期的大小是最大缓存值的值。
这是O(N)运行时:每个边(其中最多N个)在图中最多跟随3次,并且对于图中的每个节点,缓存只更新一次。它使用O(N)额外的存储空间。
答案 1 :(得分:1)
这是JavaScript中的一个实现。我没有使用JavaScript的任何奇特功能,因此可以从代码中轻松看到该算法。另一方面,它确实需要ES6支持才能运行(忘记IE):
function largestCycle(edges) {
var result, visitedFrom, startCell, cell, cells;
result = [];
visitedFrom = Array(edges.length).fill(-1);
for (startCell = 0; startCell < edges.length; startCell++) {
cells = [];
for (cell=startCell; cell>-1 && visitedFrom[cell]===-1; cell = edges[cell]) {
visitedFrom[cell] = startCell;
cells.push(cell);
}
if (cell > -1 && visitedFrom[cell] === startCell) {
cells = cells.slice(cells.indexOf(cell));
if (cells.length > result.length) result = cells;
}
}
return result;
}
// Snippet I/O
var input = document.querySelector('textarea');
var output = document.querySelector('span');
(input.oninput = function () {
// Get input as array of numbers
var edges = input.value.trim().split(/\s+/).map(Number);
// Apply algorithm
var cycle = largestCycle(edges);
// Output result
output.textContent = cycle.length + ': ' + JSON.stringify(cycle);
})(); // Execute also at page load
Input:<br>
<textarea style="width:100%">4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21</textarea><br>
Greatest Cycle: <span></span>
这在 O(n)中运行。即使外部循环同时具有嵌套循环和迭代数组的表达式(使用slice
和indexOf
),这些子迭代仅在每个单元格中执行一次,因此总的来说这仍然是 O(n)的
该函数不仅返回循环大小,还返回包含属于该循环的单元格列表的数组。这是一个很小的开销,但允许更好地验证结果。
答案 2 :(得分:1)
trincot 建议的解决方案的 Python 实现。 说明:
visitedFrom[cell] == startCell
即 0 添加到 result
数组中。def largestCycle(edges):
result = []
visitedFrom = [-1] * len(edges)
for startCell in range(0, len(edges)):
cells = []
cell = startCell
while cell > -1 and visitedFrom[cell] == -1:
visitedFrom[cell] = startCell
cells.append(cell)
cell = edges[cell]
if cell > -1 and visitedFrom[cell] == startCell:
cells_idx = cells.index(cell)
cells = cells[cells_idx:]
if len(cells) > len(result):
result = cells
return result,len(result)
size = 23
edges = [4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21]
largestCycle(edges)
答案 3 :(得分:0)
import java.util.Scanner;
class path
{
public static void main(String [] args)
{
Scanner scnr=new Scanner(System.in);
int n=scnr.nextInt();
int a[]=new int[n];
for(int i=0;i<n;i++)
{
a[i]=scnr.nextInt();
}
int path=-1;
int j;
for(int i=0;i<n;i++)
{ j=i;
int count=0;
while(true)
{
count++;
if(a[j]==-1)
{
break;
}
else if(i==a[j])
{
if(count>path)
path=count;
break;
}
else
{ int temp=j;
j=a[j];
a[temp]=-1;
}
}
}
System.out.println("my path: "+path);
}
}
答案 4 :(得分:0)
package graphsBasic;
import java.util.*;
public class LargestCycleInGraph {
public static int checkCycle(int []cell , int size , int start) {
Set<Integer> set = new HashSet<>();
set.add(start);
for(int i = start ;i< size;i++) {
if( !set.contains(cell[i]) && cell[i] != -1) {
set.add( cell[i] );
}
else return set.size() + 1; // 1 for again come to cycle node
}
return -1;
}
public static int findLargestCycle(int []cell , int size) {
int max = -1;
for(int i =0;i<size;i++) {
//if you want to find sum of largest cycle return "Set" rather than its size and check for max sum
int cyc = checkCycle(cell , size , i);
if(max < cyc)
max = cyc;
}
return max;
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int size = 23;
int []cell = {4, 4, 1, 4, 13, 8, 8, 8, 0, 8, 14, 9, 15, 11, -1, 10, 15, 22, 22, 22, 22, 22, 21};
int largestCycle = findLargestCycle(cell , size);
System.out.println("Largest cycle Length " +largestCycle);
}
}
答案 5 :(得分:0)
这是解决问题的方法,但输入格式实际上并不相同。
这是输入格式:
test cases: N
size of array: M
array elements: 1<=a(i)<=M-1 where 0<=i<=M-1
index to which last index points: C
在此问题中,我们必须在最大周期内对单元进行计数,这是代码:
class countLargestCycleMaze {
static vertex[] cells;
static class vertex {
int name;
neighbor list;
public vertex(int v, neighbor nb) {
this.name = v;
this.list = nb;
}
}
static class neighbor {
int vnum;
neighbor next;
public neighbor(int v, neighbor nb) {
this.vnum = v;
this.next = nb;
}
}
static int dfs(int v, int m) {
neighbor tmp = cells[v].list;
int c = 0;
while (tmp.vnum != m)
tmp = cells[tmp.vnum].list;
tmp = cells[tmp.vnum].list;
while (tmp.vnum != m) {
tmp = cells[tmp.vnum].list;
c++;
}
return c;
}
public static void main(String[] args) throws java.lang.Exception {
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int i, j, n, m, c;
n = Integer.parseInt(br.readLine());
while (n-- > 0) {
m = Integer.parseInt(br.readLine());
StringTokenizer st = new StringTokenizer(br.readLine());
c = Integer.parseInt(br.readLine());
if (c == 0) {
System.out.println("0");
continue;
}
cells = new vertex[m + 1];
for (i = 0; i < m; i++) {
int num = Integer.parseInt(st.nextToken());
cells[i] = new vertex(num, null);
cells[i].list = new neighbor(num, cells[i].list);
}
cells[m] = new vertex(c, null);
cells[m].list = new neighbor(c, cells[m].list);
System.out.println(dfs(0, c));
}
} catch (Exception e) {}
}
}
答案 6 :(得分:0)
def main():
size = int(input())
cell = input().split()
for i in range(0, len(cell)):
cell[i] = int(cell[i])
m = -1
for i in range(0, 23):
if m < check_cycle(cell, i):
m = check_cycle(cell, i)
print("Largest cycle is made of", m, "nodes")
def check_cycle(cell, start):
i = start
if i in cell:
cycle = [i]
j = i
while 1:
for k in cycle:
if cycle.count(k) >= 2:
if cycle[0] == cycle[-1]:
return len(cycle)-1
else:
return 0
else:
cycle.append(cell[j])
j = cell[j]
else:
return 0
main()
答案 7 :(得分:0)
public static int solution(int arr[])
{
ArrayList<Integer> sum = new ArrayList<>();
for(int i = 0; i < arr.length; i ++)
{
ArrayList<Integer> path = new ArrayList<>();
int j = i;
int tempSum = 0;
while(arr[j]<arr.length && arr[j]!=i && arr[j]!=-1 && !path.contains(j))
{
path.add(j);
tempSum+=j;
j=arr[j];
if(arr[j]==i)
{
tempSum+=j;
break;
}
}
if(j<arr.length && i == arr[j])
sum.add(tempSum);
}
if(sum.isEmpty())
return -1;
return Collections.max(sum);
}
答案 8 :(得分:0)
这是我尝试遍历图的每个节点:-
{
"compilerOptions": {
"checkJs": true,
"allowJs": true,
"outDir": "node_modules/.tmp/",
"noImplicitAny": true
},
"include": [
"index.js"
]
}
答案 9 :(得分:0)
O(n)时间复杂度解决方案仅在检查过是否访问过每个节点之后,才访问每个节点,因此每个节点仅被访问一次。
O(n)空间复杂度([n]:堆栈空间最大值+ [2 * n]:两个地图使用的最大大小)
要观察:两个节点之间始终存在唯一的路径(请检查任何测试用例),由于条件的限制,每个节点只有一个出口。
C ++代码:
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
//res stores result
int res = 0;
//visit to check in before visiting the node, to stop repeat visiting
unordered_map<int,bool> visit;
void dfs(vector<int> & a, unordered_map<int,int> &mp, int i, int k){
if(visit.find(i) != visit.end())
return;
if(a[i] == -1){
visit[i] = true;
return;
}
if(mp.find(i) != mp.end()){
res = max(res, k-mp[i]);
visit[i] = true;
return;
}
mp[i] = k;
dfs(a, mp, a[i], k+1);
visit[i] = true;
}
int main() {
int n;
cin>>n;
vector<int> a(n,0);
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++){
if(visit.find(i) == visit.end()){
unordered_map<int,int> mp;
dfs(a, mp, i, 0);
}
}
cout<<res<<endl;
return 0;
}
答案 10 :(得分:0)
C ++解决方案
#include <bits/stdc++.h>
using namespace std;
bool isCycle(vector<int> arr, int curr, vector<bool> &visited, vector<int> &path)
{
if (curr == -1)
{
return false;
}
if (visited[curr])
{
return true;
}
visited[curr] = true;
path.emplace_back(curr);
if (isCycle(arr, arr[curr], visited, path))
return true;
return false;
}
int largestSumCycle(vector<int> arr)
{
int n = arr.size();
int sum = INT_MIN;
vector<bool> visited(n, false);
for (int i = 0; i < n; i++)
{
visited[i] = true;
vector<int> path;
if (isCycle(arr, arr[i], visited, path))
sum = max(sum, accumulate(path.begin(), path.end(), 0));
visited[i] = false;
}
if (sum == INT_MIN)
return -1;
return sum;
}
答案 11 :(得分:0)
这是访谈中的一个常见问题,在同一次访谈中,他们也针对相同的细节询问了这个问题。
Q:找到NEAREST MEETING CELL(NMC)
INPUT:与上面相同,+第三行有2个数字,可以找到最接近的会议单元格。
样品输入
23
4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21
9 2(需要在网格/图形中找到相交点9,2)
输出
4
代码:
def main():
testCASES=int(input())
# testCASES=1
for case_number in range(testCASES):
meshsize=input()
mesh=input()
# mesh='4 4 1 4 13 8 8 8 0 8 14 9 15 11 -1 10 15 22 22 22 22 22 21'
det=input()
# det='9 2'
mesh=[int(x) for x in mesh.split()]
det=[int(x) for x in det.split()]
n1=det[0]
n2=det[1]
n1path=[]
n2path=[]
for i in range(len(mesh)):
if not n1path:
n1path.append(mesh[n1])
else:
n1path.append(mesh[n1path[i-1]])
if not n2path:
n2path.append(mesh[n2])
else:
n2path.append(mesh[n2path[i-1]])
nearestList=[]
try:
for x in n1path:
nearestList.append(n2path.index(x))
NEAREST_NODE=n2path[min(nearestList)]
except Exception as e:
NEAREST_NODE = -1
# print(n1path,n2path)
print(NEAREST_NODE)
main()
工作:
从给定的2个点开始走路径,并通过对最近列表的索引使用min()函数来计算n1path和n2path的第一个公共点。命名是任意的,但这就是核心算法。
它可以处理是否存在循环,并且仍然返回第一个交点。 如果找不到匹配项,则返回-1。
答案 12 :(得分:0)
使用Prims算法在节点中找到最大循环
n = int(input())
v = n
e = v+1
arr = [int(i) for i in input().split()]
graph = [[0 for _ in range(n)] for _ in range(n)]
for i in range(0, len(arr)):
graph[i][arr[i]] = 1
for i in graph:
print(i)
def min_ind(wieight, visied):
min_ = -1
ind = -1
for i in range(v):
if(wieight[i] > min_ and visied[i] == False):
min_ = wieight[i]
ind = i
return ind
def printPath(parent, i):
res = []
while(parent[i] != -1):
res.append(i)
i = parent[i]
res.append(i)
return res[::-1]
# Dijkstra
visited = [False for _ in range(v)]
wieight = [0 for _ in range(v)]
parent = [-1 for i in range(v)]
wieight[0] = 0
path = []
for _ in range(v):
u = min_ind(wieight, visited)
if(u == -1):
continue
visited[u] = True
for i in range(v):
if(graph[u][i] > 0 and visited[i] == False):
if(wieight[i] < graph[u][i]):
wieight[i] = graph[u][i]
parent[i] = u
maximum = 0
for i in range(0, len(wieight)):
print("No:", i, " Weight:", wieight[i], " Path:", end=" ")
path = (printPath(parent, i))
maximum = max(maximum, len(path))
print(path, end=" ")
print()
print("Longest Cycle: ", maximum)