Last active
July 20, 2017 05:52
-
-
Save maxint137/cab1b3f9822ebbe60bf3b93dc0e4c962 to your computer and use it in GitHub Desktop.
Find a cycle of a given length in a graph
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
void Main() | |
{ | |
var n0 = new Node<string>("n0", null); | |
var n1 = new Node<string>("n1", null); | |
var n2 = new Node<string>("n2", null); | |
var n3 = new Node<string>("n3", null); | |
var n4 = new Node<string>("n4", null); | |
var n5 = new Node<string>("n5", null); | |
var n6 = new Node<string>("n6", null); | |
var n7 = new Node<string>("n7", null); | |
var n8 = new Node<string>("n8", null); | |
// 8-shaped | |
// n1.setNodes(new Node<string>[] { n2 }); | |
// n2.setNodes(new Node<string>[] { n3, n5 }); | |
// n3.setNodes(new Node<string>[] { n4 }); | |
// n4.setNodes(new Node<string>[] { n1 }); | |
// n5.setNodes(new Node<string>[] { n6 }); | |
// n6.setNodes(new Node<string>[] { n1 }); | |
// something simple | |
// n1.setNodes(new Node[] { n2 }); | |
// n2.setNodes(new Node[] { n3, n4 }); | |
// n3.setNodes(new Node[] { n4 }); | |
// n4.setNodes(new Node[] { n1, n2 }); | |
// https://activities.tjhsst.edu/sct/lectures/1516/SCT_Tarjans_Algorithm.pdf | |
//n0.setNodes(new Node<string>[] { n0 }); | |
n1.setNodes(new Node<string>[] { n2 }); | |
n2.setNodes(new Node<string>[] { n3, n5, n6, n7 }); | |
n4.setNodes(new Node<string>[] { n7 }); | |
n5.setNodes(new Node<string>[] { n1 }); | |
n6.setNodes(new Node<string>[] { n2, n7 }); | |
n7.setNodes(new Node<string>[] { n3, n4 }); | |
n8.setNodes(new Node<string>[] { n4 }); | |
var graph = new Node<string>[] {n0, n1, n2, n3, n4, n5, n6, n7, n8}; | |
Aux.readInput(); | |
graph.hasCycleOfLength(8).Dump(); | |
// n1.DFS(_ => _.Select(n => n.name).Dump("@1"));//.Dump("DFS starting at n1"); | |
// n2.DFS(_ => _.Select(n => n.name).Dump("@2"));//.Dump("DFS starting at n2"); | |
// n3.DFS(_ => _.Select(n => n.name).Dump("@3"));//.Dump("DFS starting at n2"); | |
// n4.DFS(_ => _.Select(n => n.name).Dump("@4"));//.Dump("DFS starting at n2"); | |
// n2.DFS().Dump("DFS starting at n2"); | |
// n3.DFS().Dump("DFS starting at n3"); | |
// n4.DFS().Dump("DFS starting at n4"); | |
// n5.DFS().Dump("DFS starting at n4"); | |
// n4.DFS().Dump("DFS starting at n4"); | |
// n4.DFS().Dump("DFS starting at n4"); | |
// graph.hasCycleOfLength(3).Dump("graph.hasCycleOfLength(3)"); | |
} | |
delegate void CycleDetected<T>(IEnumerable<Node<T>> cycle); | |
class Node<T> | |
{ | |
public string name { get; set; } | |
public List<Node<T>> nodes { get; set; } | |
public void setNodes(IEnumerable<Node<T>> ns) | |
{ | |
nodes = new List<Node<T>>(); | |
if (null == ns) | |
{ | |
return; | |
} | |
nodes.AddRange(ns); | |
} | |
public Node(string name, IEnumerable<Node<T>> ns) | |
{ | |
this.name = name; | |
this.setNodes(ns); | |
} | |
} | |
static class Aux | |
{ | |
class ListIntersectComparer : IEqualityComparer<List<string>> | |
{ | |
public bool Equals(List<string> x, List<string> y) | |
{ | |
return x.Intersect(y).Any(); | |
} | |
public int GetHashCode(List<string> obj) => 7; | |
} | |
public class MyStringListComparer : IEqualityComparer<List<string>> | |
{ | |
public bool Equals(List<string> x, List<string> y) | |
{ | |
return x.Zip(y, (_x, _y) => _x == _y).All(_ => _); | |
} | |
public int GetHashCode(List<string> obj) => 7; | |
} | |
public static bool hasCycleOfLength<T>(this Node<T>[] graph, int m) | |
{ | |
var allCycles = new HashSet<List<string>>(new MyStringListComparer()); | |
foreach (var n in graph) | |
{ | |
n.DFS(cyc => | |
{ | |
allCycles | |
.Add(cyc.Select(_ => _.name) | |
.OrderBy(_ => _) | |
.ToList() | |
); | |
}); | |
} | |
allCycles.Dump("Unique cycles"); | |
if (allCycles.Any(_ => 1 == _.Count())) | |
{ | |
// cycle of 1 - we can do anything! | |
return true; | |
} | |
// otherwise check if the diophantine equation has a solution | |
// but first - need to group the connected cycles | |
var connectedCycles = allCycles | |
.GroupBy(_=>_, new ListIntersectComparer()) | |
.Select(_=>_.Select(__=>__.Count()).Distinct()) | |
.Dump("Connected cycles' lengths") | |
; | |
// UF: need to make sure we have a positive solution? | |
if (!connectedCycles.Select(_ => 0 == m % gcd(_)).Any(_ => _)) | |
{ | |
return false; | |
} | |
foreach (var cc in connectedCycles) | |
{ | |
if (findAllPositiveSolutions(cc, m).Any()) | |
{ | |
return true; | |
} | |
} | |
return false; | |
} | |
static IEnumerable<int> findAllPositiveSolutions(IEnumerable<int> ks, int c) | |
{ | |
if (ks.Count() < 2) | |
{ | |
if (0 == c % ks.First()) | |
{ | |
yield return c / ks.First(); | |
} | |
yield break; | |
} | |
foreach (var x0 in Enumerable.Range(0, c / ks.First())) | |
{ | |
var tail = findAllPositiveSolutions(ks.Skip(1), c - x0 * ks.First()).ToList(); | |
if (tail.Any()) | |
{ | |
yield return x0; | |
foreach (var t in tail) | |
{ | |
yield return t; | |
} | |
} | |
} | |
} | |
static int gcd(IEnumerable<int> bs) | |
{ | |
if (1 < bs.Count()) | |
{ | |
return gcd(bs.First(), bs.Skip(1)); | |
} | |
return bs.First(); | |
} | |
static int gcd(int a, IEnumerable<int> bs) | |
{ | |
if (bs.Count() < 2) | |
{ | |
return gcd(a, bs.First()); | |
} | |
return gcd(gcd(a, bs.First()), bs.Skip(1)); | |
} | |
static int gcd(int a, int b) | |
{ | |
return (a % b == 0) ? Math.Abs(b) : gcd(b, a % b); | |
} | |
public static IEnumerable<Node<T>> DFS<T>(this Node<T> start, CycleDetected<T> cd) | |
{ | |
var res = new Stack<Node<T>>(); | |
DFS_helper(start, res, cd); | |
return res; | |
} | |
static void DFS_helper<T>(Node<T> start, Stack<Node<T>> found, CycleDetected<T> cd) | |
{ | |
if (found.Any() | |
&& found.Last().name == start.name) | |
{ | |
cd(found.Reverse()); | |
return; | |
} | |
if (found.Any(_ => _.name == start.name)) | |
{ | |
return; | |
} | |
found.Push(start); | |
foreach (var n in start.nodes) | |
{ | |
DFS_helper(n, found, cd); | |
} | |
found.Pop(); | |
} | |
public static void readInput() | |
{ | |
var matrix = new List<string>(); | |
var graph = new List<Node<string>>(); | |
foreach (var i in Enumerable.Range(0, Int16.Parse(Console.ReadLine()))) | |
{ | |
matrix.Add(Console.ReadLine()); | |
graph.Add(new Node<string>($"{graph.Count()}", null)); | |
} | |
foreach (var l in Enumerable.Range(0, matrix.Count())) | |
{ | |
matrix[l] | |
.ToCharArray() | |
.Select((_, i) => | |
{ | |
if ('1' == _) | |
{ | |
graph[l].nodes.Add(graph[i]); | |
} | |
return true; | |
} | |
).Count(); | |
} | |
var m = Int16.Parse(Console.ReadLine()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment