1
c algorithm 595, collected algorithms from acm.
2
c algorithm appeared in acm-trans. math. software, vol.9, no. 1,
3
c mar., 1983, p. 131-138.
4
c this program finds one or more hamiltonian circuits in a
5
c directed graph of n vertices and m arcs.
6
c input : n number of vertices, ar=ls, pr=lp-1
7
subroutine hamil(n,m,np1,pr,ar,s,nc,nb,
8
* pc,ac,vr,vc,p,subr,rbus,tor)
9
integer pr(np1),pc(np1),ar(m),ac(m),s(n),vr(n),
10
* vc(n),p(n),subr(n),rbus(n),tor(n)
11
c exact procedure to find a single hamiltonian circuit, if one exists.
17
call hproc(n,pr,ar,nout,nc,nb,s,n+1,pr(n+1),pc,ac,vr, vc,
19
c exact procedure to find all the hamiltonian circuits.
22
c call hproc(n,pr,ar,nout,nc,nb,s,n+1,pr(n+1),pc,ac,vr,vc,
23
c * p, subr, rbus, tor)
24
c heuristic procedure to find a single hamiltonian
25
c circuit, if one exists, without performing more than 2 backtrackings.
28
c call hproc(n,pr,ar,nout,nc,nb,s,n+1, pr(n+1),pc,ac,vr,vc,
30
c heuristic procedure to find a single hamiltonian
31
c circuit, if one exists, without performing more than 4 backtrackings.
34
c call hproc(n,pr,ar,nout,nc,nb,s,n+1,pr(n+1),pc,ac,vr,vc,
36
c heuristic procedure to find at most 2
37
c hamiltonian circuits, without performing more than 5 backtrackings.
40
c call hproc(n,pr,ar,-1,nc,nb,s,n+1,pr(n+1),pc,ac,vr,vc,
45
subroutine hproc(n,pr,ar,kw,nc,nb,s,np1,m,pc,ac,vr,vc,
48
c subroutine to find one or more hamiltonian circuits in a
49
c directed graph of n vertices ( n .gt. 1 ) represented
50
c by the integers 1, 2, ..., n and m arcs.
52
c hproc is based on an enumerative algorithm and can be used
53
c either as an exact procedure or as a heuristic procedure
54
c (by limiting the number of backtrackings allowed).
56
c entrance to hproc is achieved by using the statement
57
c call hproc(n,pr,ar,kw,nc,nb,s,n+1,pr(n+1),pc,ac,vr,vc,
60
c the values of the first six parameters must be defined
61
c by the user prior to calling hproc. hproc needs 2 arrays ( pr
62
c and pc ) of length n + 1 , 2 arrays ( ar and ac )
63
c of length m and 7 arrays ( s , vr , vc , subr ,
64
c rbus and tor ) of length n . these arrays must be
65
c dimensioned by the user in the calling program.
67
c hproc calls 5 subroutines: pathp, fupd, bupd, iupd, rarc.
68
c meaning of the input parameters:
69
c n = number of vertices.
70
c pr(i) = sum of the out-degrees of vertices 1, ..., i-1
71
c ( pr(1) = 0 , pr(n+1) = m ).
72
c ar = adjacency list. the elements from ar(pr(i)+1) to
73
c ar(pr(i+1)) are a record containing,in any order,
74
c all the vertices j such that arc (i,j) exists.
75
c the graph should not contain arcs starting and
76
c ending at the same vertex.
77
c kw = unit tape on which to write the hamiltonian cir-
78
c cuits found, according to format 20i5 . kw = - 1
79
c if no writing is desired. the circuits are written
80
c as ordered sequences of n vertices.
82
c meaning of the input-output parameters:
83
c nc(input) = upper bound on the number of hamiltonian
84
c circuits to be found ( nc = - 1 if all the
85
c hamiltonian circuits are to be found).
86
c nc(output) = number of hamiltonian circuits found.
87
c nb(input) = - 1 if hproc must be executed as an exact
89
c = upper bound on the number of backtrackings if
90
c hproc must be executed as a heuristic procedure.
91
c nb(output) = number of backtrackings performed. when hproc
92
c has been executed as a heuristic procedure,
93
c if nb(output) .lt. nb(input) then the
94
c result obtained is exact.
96
c meaning of the output parameter:
97
c s(i) = i-th vertex in the last hamiltonian circuit found.
99
c on return of hproc n, pr and kw are unchanged, while in
100
c ar the order of the elements within each record may be
103
c meaning of the work arrays:
104
c pc(i) = sum of the in-degrees of vertices 1, ..., i-1
106
c ac = adjacency list (backward). the elements from
107
c ac(pc(i)+1) to ac(pc(i+1)) contain, in any
108
c order, all the vertices j such that arc (j,i)
110
c when an arc is removed from the graph at the k-th level
111
c of the branch-decision tree, the corresponding elements
112
c ar(q) and ac(t) are set to - (k*(n+1) + ar(q)) and
113
c to - (k*(n+1) + ac(t)) , respectively.
114
c vr(i) = current out-degree of vertex i .
115
c vc(i) = current in-degree of vertex i .
116
c subr(i) = - (k*(n+1) + j) if arc (i,j) was implied at
117
c the k-th level of the branch-decision tree.
119
c rbus(i) = - j if arc (j,i) is currently implied.
121
c tor(k) = q*(m+1) + t if the arc going from s(k) to the
122
c root, corresponding to ar(q) and to ac(t),
123
c was removed from the graph at the k-th level
124
c of the branch-decision tree.
126
c p(i) = pointer for the forward step. the next arc
127
c starting from i to be considered in the
128
c branch-decision tree is (i,ar(pr(i)+p(i)).
130
c meaning of the main work simple variables:
131
c jr = root. the hamiltonian circuits are determined as
132
c paths starting and ending at jr .
133
c k = current level of the branch-decision tree.
134
c m = number of arcs.
135
c mp1 = m + 1 (used for packing tor ).
136
c np1 = n + 1 (used for packing ar , ac and subr )
138
integer pr(np1), pc(np1), ar(m), ac(m), s(n), vr(n), vc(n), p(n),
139
* subr(n), rbus(n), tor(n)
141
c s t e p 0 (initialize).
157
if (vr(i).eq.0) return
165
if (vc(i).eq.0) return
166
pc(i+1) = pc(i) + vc(i)
180
c select as root jr the vertex i with maximum vc(i)
181
c (break ties by choosing i with minimum vr(i) ).
186
if (vc(i)-maxe) 100, 70, 80
187
70 if (vr(i).ge.minu) go to 100
197
c s t e p 1 (search for implied arcs).
200
if (vr(j).eq.1) go to 130
201
if (vc(j).eq.1) go to 170
203
c no further arc can be implied.
205
c arc (j,jl) is implied because vr(j) = 1 .
209
if (ar(l).gt.0) go to 150
212
c find the starting vertex it1 and the ending vertex it2
213
c of the largest path of implied arcs containing (j,jl) .
214
call pathp(j, jl, subr, rbus, ar, pr, s, n, np, it1, it2, k, jr,
216
if (np.eq.0) go to 160
217
if (np.eq.(-1)) go to 340
218
c subroutine pathp found a hamiltonian circuit.
221
160 subr(j) = k1 - jl
223
c remove from the graph all arcs terminating at jl .
224
call iupd(j, jl, l, ac, ar, pc, pr, vc, vr, k1, n, m, np1)
225
if (j.eq.0) go to 340
227
c arc (jl,j) is implied because vc(j) = 1 .
231
if (ac(l).gt.0) go to 190
234
c find the starting vertex it1 and the ending vertex it2
235
c of the largest path of implied arcs containing (jl,j) .
236
call pathp(jl, j, subr, rbus, ar, pr, s, n, np, it1, it2, k, jr,
238
if (np.eq.0) go to 200
239
if (np.eq.(-1)) go to 340
240
c subroutine pathp found a hamiltonian circuit.
244
200 subr(jl) = k1 - j
246
c remove from the graph all arcs emanating from jl .
247
call iupd(j, jl, l, ar, ac, pr, pc, vr, vc, k1, n, m, np1)
248
if (j.eq.0) go to 340
249
c if arc (it2,it1) is in the graph, remove it.
250
210 call rarc(it2, it1, ar, ac, pr, pc, vr, vc, k1, jj, ll, n, m, np1)
251
if (jj.eq.(-1)) go to 340
254
c s t e p 2 (add implied arcs to s ).
257
if (subr(i).eq.0) go to 230
258
jsubr = -subr(i) + subr(i)/np1*np1
259
if (jsubr.eq.jr) go to 340
262
if (k.ne.n) go to 220
263
if (subr(jsubr).lt.0) go to 320
266
c s t e p 3 (branch).
268
230 l1 = pr(i) + p(i)
270
if (l1.gt.l2) go to 340
271
c find the next arc (i,jl) to be added to s .
277
if (jl.lt.0) go to 310
278
if (vr(jl).gt.0) go to 260
279
if (subr(jl).eq.0) go to 310
280
if (jl.eq.jr) go to 310
282
240 iend = -subr(iend) + subr(iend)/np1*np1
283
if (subr(iend).ne.0) go to 240
284
if (vc(jl).lt.vr(iend)) go to 250
285
score = vr(iend)*n + vc(jl)
287
250 score = vc(jl)*n + vr(iend)
289
260 if (vc(jl).lt.vr(jl)) go to 270
290
score = vr(jl)*n + vc(jl)
292
270 score = vc(jl)*n + vr(jl)
293
280 if (dens.le.score) go to 290
296
290 if (j1.eq.0) go to 300
301
if (j1.eq.0) go to 340
305
if (j2.eq.0) j2 = pr(i+1) + 1
310
c remove from the graph all arcs emanating from i .
311
call fupd(ar, ac, pr, pc, vr, vc, i, k1, n, m, np1)
312
c remove from the graph all arcs terminating at jl .
313
call fupd(ac, ar, pc, pr, vc, vr, jl, k1, n, m, np1)
315
c if arc (jl,jr) is in the graph, remove it.
316
call rarc(jl, jr, ar, ac, pr, pc, vr, vc, k1, jj, ll, n, m, np1)
317
if (jj.eq.0) go to 110
318
if (jj.eq.(-1)) go to 340
322
c s t e p 4 (hamiltonian circuit found).
325
if (kw.eq.(-1)) go to 330
327
330 if (nc.eq.nco) go to 430
330
c s t e p 5 (backtrack).
332
340 if (k.le.1) go to 430
336
if (subr(ja).eq.0) go to 350
337
c backtracking for an implied arc.
340
350 if (nb.eq.nbo) go to 430
345
c backtracking for the arcs implied at level k .
348
if (subr(j).gt.k1) go to 360
349
if (subr(j).lt.k2) go to 360
355
if (iff.eq.1) go to 370
356
c no arc was implied at level k .
357
call bupd(ar, ac, pr, pc, vr, vc, i, k1, k2, n, m, np1)
358
call bupd(ac, ar, pc, pr, vc, vr, s(k), k1, k2, n, m, np1)
359
if (tor(k).eq.0) go to 420
368
c at least one arc was implied at level k .
374
if (jl.gt.k1) go to 400
375
if (jl.lt.k2) go to 400
382
if (k1-ac(ll).eq.j) go to 390
391
c re-store the original vector ar .
394
if (ar(j).gt.0) go to 440
395
ar(j) = -ar(j) + ar(j)/np1*np1
399
subroutine pathp(i,j,subr,rbus,ar,pr,s,n,np,i1,i2,k,
401
c subroutine to find the starting vertex i1 and the ending
402
c vertex i2 of the largest path of implied arcs containing
404
c meaning of the output parameter np :
405
c np = 0 if the path contains l .lt. n vertices.
406
c = 1 if the path contains n vertices and arc (i2,i1)
407
c exists (the hamiltonian circuit is stored in s )
408
c = -1 if the path contains n vertices but arc (i2,i1)
410
integer subr(n), rbus(n), ar(m), pr(np1), s(n)
414
10 if (rbus(i1).eq.0) go to 20
420
30 if (subr(i2).eq.0) go to 40
421
i2 = -subr(i2) + subr(i2)/np1*np1
426
c the path contains n vertices.
431
if (ar(l).lt.0) go to 50
432
if (ar(l).eq.i1) go to 70
434
50 if (k1-ar(l).eq.i1) go to 70
436
c no hamiltonian circuit can be determined.
439
c a hamiltonian circuit exists. store it in s .
445
80 if (l.eq.k) go to 90
454
subroutine fupd(a1, a2, p1, p2, v1, v2, i1, k1, n, m, np1)
455
c forward step updating
456
integer a1(m), a2(m), p1(np1), p2(np1), v1(n), v2(n)
460
if (a1(j).lt.0) go to 30
465
if (a2(l).eq.i1) go to 20
467
20 v2(ia) = v2(ia) - 1
474
subroutine bupd(a1, a2, p1, p2, v1, v2, ii, k1, k2, n, m, np1)
475
c backtracking step updating
476
integer a1(m), a2(m), p1(np1), p2(np1), v1(n), v2(n)
480
if (a1(l).gt.k1) go to 30
481
if (a1(l).lt.k2) go to 30
488
if (k1-a2(ll).eq.ii) go to 20
495
subroutine iupd(ia, ib, l, a1, a2, p1, p2, v1, v2, k1, n, m, np1)
496
integer a1(m), a2(m), p1(np1), p2(np1), v1(n), v2(n)
497
c updating for implied arc
502
if (iarc.lt.0) go to 40
503
if (v2(iarc).ne.1) go to 10
504
if (iarc.ne.ia) go to 50
510
if (a2(jj).eq.ib) go to 30
512
30 a2(jj) = k1 - a2(jj)
513
v2(iarc) = v2(iarc) - 1
521
subroutine rarc(ia, ib, ar, ac, pr, pc, vr, vc, k1, jj, ll, n, m,
523
c subroutine to remove arc (ia,ib) from the graph.
524
c meaning of the output parameters jj and ll :
525
c jj = location of the element of ar corresponding to the removed arc.
526
c = 0 if arc (ia,ib) is not in the graph.
527
c = -1 if, after the removal of arc (ia,ib) , the graph
528
c would admit no hamiltonian circuit.
529
c ll = location of the element of ac corresponding to the
530
c removed arc (defined only if jj .gt. 0 ).
531
integer ar(m), ac(m), pr(np1), pc(np1), vr(n), vc(n)
535
if (ar(jj).lt.0) go to 20
536
if (ar(jj).ne.ib) go to 20
540
if (ac(ll).eq.ia) go to 30
543
c arc (ia,ib) is not in the graph.
546
30 if (vr(ia).eq.1) go to 40
547
if (vc(ib).eq.1) go to 40
553
c arc (ia,ib) cannot be removed from the graph.