⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rmst.c

📁 生成直角Steiner树的程序包
💻 C
字号:
/***********************************************************************	File:	rmst.c	Rev:	b-1	Date:	02/28/2001	Copyright (c) 1993, 2001 by David M. Warme************************************************************************	Routines to compute rectilinear Minimum Spanning Trees.	Also contains the 1-Steiner heuristic of Kahng and Robins.************************************************************************	Modification Log:	a-1:	02/20/93	warme		: Created.	b-1:	02/28/2001	warme		: Changes for 3.1 release.		: Use common Kruskal code in mst.c.		: Rename build_edges to be build_rect_edges.************************************************************************/#include "dsuf.h"#include "emptyr.h"#include "steiner.h"/* * Global Routines */int			kahng_robins (struct pset *, dist_t, struct edge *);dist_t			kahng_robins_length (struct pset *, dist_t);int			rect_mst (struct pset *, struct edge *, bitmap_t *);dist_t			rect_mst_length (struct pset *);/* * External References */	/* none *//* * Local Routines */static int		build_rect_edges (struct pset *,					  struct edge **,					  int,					  bitmap_t *);static dist_t		kr_main (struct pset *, dist_t);/* * This routine computes the total length of the Minimum Spanning Tree * of the given set of points. */	dist_trect_mst_length (struct pset *		pts	/* IN - point set to find MST length of. */){int		i;int		nedges;dist_t		total;struct edge *	ep;struct edge *	edges;	edges = NEWA (pts -> n - 1, struct edge);	nedges = rect_mst (pts, &edges [0], NULL);	if (nedges NE pts -> n - 1) {		fatal ("mst_length: Bug 1.");	}	total = 0;	ep = &edges [0];	for (i = 0; i < nedges; i++) {		total += ep -> len;		++ep;	}	free ((char *) edges);	return (total);}/* * This routine computes a rectilinear Minimum Spanning Tree for the * given point set.  The output is a list of edges. * * The caller may optionally provide an empty rectangle bit-matrix. * This info can substantially speed up the algorithm and decrease * memory requirements by limiting the number of edges stored and sorted. * If such info is unavailable, supply empty_rect = NULL. */	intrect_mst (struct pset *		pts,		/* IN - point set. */struct edge *		edges,		/* OUT - edge list. */bitmap_t *		empty_rect	/* IN - empty rectangle info */){int		nedges;int		mst_edge_count;struct edge *	edge_array;	nedges = build_rect_edges (pts, &edge_array, 0, empty_rect);	mst_edge_count = mst_edge_list (pts -> n,					nedges,					&edge_array [0],					edges);	free ((char *) edge_array);	return (mst_edge_count);}/* * This routine builds an edge-list containing all pairs of points. * * If non-NULL, the empty-rectangle info is used to greatly reduce * the number of edges produced. */	static	intbuild_rect_edges (struct pset *		pts,		/* IN - set of points */struct edge **		edges_out,	/* OUT - edge list */int			at_least,	/* IN - allocate at least this many */					/*	edges */bitmap_t *		empty_rect	/* IN - empty rectangle info */){int		i;int		j;int		n;int		nedges;int		nalloc;struct edge *	edges;struct point *	p1;struct point *	p2;	n = pts -> n;	if (empty_rect EQ NULL) {		/* Generate all N choose 2 edges. */		nedges = (n * (n - 1)) >> 1;		nalloc = nedges;		if (nalloc < at_least) {			nalloc = at_least;		}		edges = NEWA (nalloc, struct edge);		*edges_out = edges;		p1 = &(pts -> a [0]);		for (i = 0; i < n; i++, p1++) {			p2 = (p1 + 1);			for (j = i + 1; j < n; j++, p2++) {				edges -> len	= RDIST (p1, p2);				edges -> p1	= ((pnum_t) i);				edges -> p2	= ((pnum_t) j);				++edges;			}		}	}	else {		/* Generate a sparse set of edges. */		nedges = count_empty_rectangles (empty_rect, n);		nalloc = nedges;		if (nalloc < at_least) {			nalloc = at_least;		}		edges = NEWA (nalloc, struct edge);		*edges_out = edges;		p1 = &(pts -> a [0]);		for (i = 0; i < n; i++, p1++) {			p2 = (p1 + 1);			for (j = i + 1; j < n; j++, p2++) {				if (NOT is_empty_rectangle (empty_rect, i, j)) continue;				edges -> len	= RDIST (p1, p2);				edges -> p1	= ((pnum_t) i);				edges -> p2	= ((pnum_t) j);				++edges;			}		}	}	return (nedges);}/* * This routine computes an approximate Steiner Minimal Tree using the * heuristic method of Kahng and Robins. * * Inputs:	pts	- the input point set -- MODIFIED to contain *			  additional Steiner points. * *		limit	- we quit if we ever get a tree shorter than this. * * Outputs:	edges	- The list of edges in the Steiner tree. * * Returns:		- Number of edges in Steiner tree. */	intkahng_robins (struct pset *	pts,		/* IN/OUT - terminals and steiner points. */dist_t		limit,		/* IN - quit if tree below this in length. */struct edge *	edges		/* OUT - edge list for Steiner tree. */){int		nedges;	/* Do the Kahng-Robins stuff -- ignore the resulting tree length... */	(void) kr_main (pts, limit);	nedges = rect_mst (pts, edges, NULL);	return (nedges);}/* * This routine computes the LENGTH of an approximate Steiner Minimal Tree * using the heuristic method of Kahng and Robins.  We use this routine * when we don't care what the tree looks like and we only want to know * its length. * * Inputs:	pts	- the input point set. *		limit	- we quit if we ever get a tree shorter than this. * * Returns:		- length of Steiner tree obtained. */	dist_tkahng_robins_length (struct pset *	in_pts,		/* IN - terminals. */dist_t		limit		/* IN - quit if tree below this in length. */){int		n;dist_t		len;struct pset *	pts_copy;	n = in_pts -> n;	/* Make a temporary buffer big enough to handle the	*/	/* additional Steiner points that KR will append...	*/	pts_copy = NEW_PSET (2 * n);	/* Make a local copy of the point set that we can modify... */	COPY_PSET (pts_copy, in_pts);	len = kr_main (pts_copy, limit);	free ((char *) pts_copy);	return (len);}/* * This routine is the guts of the Kahng-Robins heuristic for computing * an approximate Steiner Minimal Tree. * * Inputs:	pts	- the input point set -- MODIFIED to contain *			  additional Steiner points. * *		limit	- we quit if we ever get a tree shorter than this. * * Returns:		- length of approximate Steiner Minimal Tree. */	static	dist_tkr_main (struct pset *	pts,		/* IN/OUT - terminals and steiner points. */dist_t		limit		/* IN - quit if tree below this in length. */){int		i;int		j;int		k;int		m;int		n;int		nterms;int		max_points;int		max_edges;int		components;dist_t		last;dist_t		best;dist_t		len;int		best_j;int		best_k;int		nedges;struct point *	p1;struct point *	p2;struct point *	p3;struct point *	newpt;struct edge *	ep;struct edge *	endp;struct edge *	ep1;struct edge *	ep2;struct edge *	endp1;struct edge *	endp2;int		root1;int		root2;int		kmasks;bitmap_t *	mark_rowp;int		new_nedges;struct point	bestpt;struct edge *	new_edges;struct edge *	edge_array;bitmap_t *	mark;struct dsuf	sets;	nterms		= pts -> n;	kmasks		= BMAP_ELTS (nterms);	max_points	= nterms + nterms - 2;	max_edges	= max_points * (max_points - 1) / 2;	new_edges	= NEWA (max_points, struct edge);	mark		= NEWA (nterms * kmasks, bitmap_t);	nedges = build_rect_edges (pts, &edge_array, max_edges, NULL);	sort_edge_list (&edge_array [0], nedges);	/* We know that build-edges gives us edges having vertices	*/	/* in the range of 0 through nterms - 1, so we don't have to	*/	/* do the sparse makeset's.  We use a union-find big enough to	*/	/* handle LOTS of added Steiner points!				*/	dsuf_create (&sets, max_points);	for (i = 0; i < nterms; i++) {		dsuf_makeset (&sets, i);	}	components = nterms;	ep = &edge_array [0];	endp = ep + nedges;	len = 0;	while (components > 1) {		if (ep >= endp) {			/* Ran out of edges before MST built! */			fatal ("kahng_robins: Bug 1.");		}		root1 = dsuf_find (&sets, ep -> p1);		root2 = dsuf_find (&sets, ep -> p2);		if (root1 NE root2) {			dsuf_unite (&sets, root1, root2);			len += ep -> len;			--components;		}		++ep;	}	best = len;	memset ((char *) mark, 0, nterms * kmasks * sizeof (bitmap_t));	/* Mark the diagonal to dis-allow terminals as steiners. */	mark_rowp = &mark [0];	for (i = 0; i < nterms; i++) {		SETBIT (mark_rowp, i);		mark_rowp += kmasks;	}	n = nterms;	newpt = &(pts -> a [n]);	for (i = 0; (i < nterms) AND (n < max_points); i++) {		last = best;		memset (newpt, 0, sizeof (*newpt));		newpt -> pnum = ((pnum_t) n);		mark_rowp = &mark [0];		p1 = &(pts -> a [0]);		for (j = 0; j < nterms; mark_rowp += kmasks, p1++, j++) {			newpt -> x = p1 -> x;			p2 = &(pts -> a [0]);			for (k = 0; k < nterms; p2++, k++) {				if (BITON (mark_rowp, k)) continue;				newpt -> y = p2 -> y;				ep2 = &new_edges [0];				p3 = &(pts -> a [0]);				new_nedges = 0;				for (m = 0; m < n; p3++, m++) {					ep2 -> p1	= n;					ep2 -> p2	= m;					ep2 -> len	= RDIST (newpt, p3);					++new_nedges;					++ep2;				}				sort_edge_list (&new_edges [0], new_nedges);				for (m = 0; m <= n; m++) {					dsuf_makeset (&sets, m);				}				components = n + 1;				ep1	= &edge_array [0];				endp1	= ep1 + nedges;				ep2	= &new_edges [0];				endp2	= ep2 + new_nedges;				len	= 0;				while (components > 1) {					if (ep1 < endp1) {						if (ep2 < endp2) {							if (ep1 -> len < ep2 -> len) {								ep = ep1++;							}							else {								ep = ep2++;							}						}						else {							ep = ep1++;						}					}					else if (ep2 < endp2) {						ep = ep2++;					}					else {						fatal ("kahng_robins: Bug 2.");					}					root1 = dsuf_find (&sets, ep -> p1);					root2 = dsuf_find (&sets, ep -> p2);					if (root1 NE root2) {						dsuf_unite (&sets, root1, root2);						len += ep -> len;						--components;					}				}				if (len < best) {					bestpt = *newpt;					best = len;					best_j = j;					best_k = k;					if (best < limit) break;				}			}			if (best < limit) break;		}		if (best < limit) {			/* Include this point in the output... */			++n;			break;		}		if (best >= last) break;		/* Avoid trying this steiner point again... */		SETBIT (&mark [best_j * kmasks], best_k);		/* Re-create edges for best point, and merge into */		/* list of all edges, maintaining sorted order... */		*newpt = bestpt;		p3 = &(pts -> a [0]);		ep = &new_edges [0];		new_nedges = 0;		for (m = 0; m < n; p3++, m++) {			ep -> p1	= n;			ep -> p2	= m;			ep -> len	= RDIST (newpt, p3);			++ep;			++new_nedges;		}		sort_edge_list (&new_edges [0], new_nedges);		ep1	= &edge_array [0];		endp1	= ep1 + nedges;		ep2	= &new_edges [0];		endp2	= ep2 + new_nedges;		ep	= endp1 + new_nedges;		nedges += new_nedges;		while (ep2 < endp2) {			if (ep1 < endp1) {				if (endp1 [-1].len >= endp2 [-1].len) {					*--ep = *--endp1;				}				else {					*--ep = *--endp2;				}			}			else {				*--ep = *--endp2;			}		}		/* Edge list updated.  Now add best point to	*/		/* the set and try for another.			*/		++n;		++newpt;	}	pts -> n = n;	dsuf_destroy (&sets);	free ((char *) edge_array);	free ((char *) mark);	free ((char *) new_edges);	return (best);}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -