This answers a different question: a cycle is not necessarily simple.
You can use the following dynamic programming solution:
fun dfs(v, start_v, c_pos, visited_vertices):
if c_pos = c.length then
// Used all edges
if v = start_v then
// Returned to the starting vertex
visited_vertices is the answer for the problem
if was[v, start_v, c_pos] then
// We've already been in this state and didn't find an answer
was[v, start_v, c_pos] <- true
for each vertex u such that d(v,u) = c[c_pos] do
// u is a possible next vertex on the path
dfs(u, start_v, c_pos + 1, visited_vertices + [u])
set all was[u, v, pos] to false
for each vertex v do
dfs(v, v, 0, [v])
The core is the
dfs function: we've started a path at vertex
start_v, visited vertices
visited_vertices and currently stay at vertex
v. During this, we've used weights
c[c_pos - 1] from the list
c. (Note that
c_pos are actually redundant since they can be recovered from
visited_vertices, but I left them for clarity).
c_pos = c.length, then we've used the entire list
c. If we've returned to the original vertex (i.e.
v = start_v), then we've found the required cycle.
Otherwise, the function tries to find the next edge in the path. It simply tries all next vertices
u (such that
d(u,v) matches the next expected length) and runs
dfs from them.
The main optimization is dynamic programming. If we've already been in some state and didn't find an answer, then we abandon the current path. Note that
visited_vertices doesn't matter for the state (since visited vertices don't affect whether we can find the rest of the path): we only care about starting vertex, current vertex, and the number of used edges.
Therefore, the total running time is $O(n^3 \cdot c.length)$: there are $O(n^2 \cdot c.length)$ states, and for each state we need $O(n)$ time.