You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
259 lines
7.1 KiB
259 lines
7.1 KiB
/*
|
|
* Copyright 1997, Regents of the University of Minnesota
|
|
*
|
|
* mincover.c
|
|
*
|
|
* This file implements the minimum cover algorithm
|
|
*
|
|
* Started 8/1/97
|
|
* George
|
|
*
|
|
* $Id: mincover.c 9942 2011-05-17 22:09:52Z karypis $
|
|
*/
|
|
|
|
#include "metislib.h"
|
|
|
|
/*************************************************************************
|
|
* Constants used by mincover algorithm
|
|
**************************************************************************/
|
|
#define INCOL 10
|
|
#define INROW 20
|
|
#define VC 1
|
|
#define SC 2
|
|
#define HC 3
|
|
#define VR 4
|
|
#define SR 5
|
|
#define HR 6
|
|
|
|
|
|
/*************************************************************************
|
|
* This function returns the min-cover of a bipartite graph.
|
|
* The algorithm used is due to Hopcroft and Karp as modified by Duff etal
|
|
* adj: the adjacency list of the bipartite graph
|
|
* asize: the number of vertices in the first part of the bipartite graph
|
|
* bsize-asize: the number of vertices in the second part
|
|
* 0..(asize-1) > A vertices
|
|
* asize..bsize > B vertices
|
|
*
|
|
* Returns:
|
|
* cover : the actual cover (array)
|
|
* csize : the size of the cover
|
|
**************************************************************************/
|
|
void MinCover(idx_t *xadj, idx_t *adjncy, idx_t asize, idx_t bsize, idx_t *cover, idx_t *csize)
|
|
{
|
|
idx_t i, j;
|
|
idx_t *mate, *queue, *flag, *level, *lst;
|
|
idx_t fptr, rptr, lstptr;
|
|
idx_t row, maxlevel, col;
|
|
|
|
mate = ismalloc(bsize, -1, "MinCover: mate");
|
|
flag = imalloc(bsize, "MinCover: flag");
|
|
level = imalloc(bsize, "MinCover: level");
|
|
queue = imalloc(bsize, "MinCover: queue");
|
|
lst = imalloc(bsize, "MinCover: lst");
|
|
|
|
/* Get a cheap matching */
|
|
for (i=0; i<asize; i++) {
|
|
for (j=xadj[i]; j<xadj[i+1]; j++) {
|
|
if (mate[adjncy[j]] == -1) {
|
|
mate[i] = adjncy[j];
|
|
mate[adjncy[j]] = i;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Get into the main loop */
|
|
while (1) {
|
|
/* Initialization */
|
|
fptr = rptr = 0; /* Empty Queue */
|
|
lstptr = 0; /* Empty List */
|
|
for (i=0; i<bsize; i++) {
|
|
level[i] = -1;
|
|
flag[i] = 0;
|
|
}
|
|
maxlevel = bsize;
|
|
|
|
/* Insert free nodes into the queue */
|
|
for (i=0; i<asize; i++)
|
|
if (mate[i] == -1) {
|
|
queue[rptr++] = i;
|
|
level[i] = 0;
|
|
}
|
|
|
|
/* Perform the BFS */
|
|
while (fptr != rptr) {
|
|
row = queue[fptr++];
|
|
if (level[row] < maxlevel) {
|
|
flag[row] = 1;
|
|
for (j=xadj[row]; j<xadj[row+1]; j++) {
|
|
col = adjncy[j];
|
|
if (!flag[col]) { /* If this column has not been accessed yet */
|
|
flag[col] = 1;
|
|
if (mate[col] == -1) { /* Free column node was found */
|
|
maxlevel = level[row];
|
|
lst[lstptr++] = col;
|
|
}
|
|
else { /* This column node is matched */
|
|
if (flag[mate[col]])
|
|
printf("\nSomething wrong, flag[%"PRIDX"] is 1",mate[col]);
|
|
queue[rptr++] = mate[col];
|
|
level[mate[col]] = level[row] + 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (lstptr == 0)
|
|
break; /* No free columns can be reached */
|
|
|
|
/* Perform restricted DFS from the free column nodes */
|
|
for (i=0; i<lstptr; i++)
|
|
MinCover_Augment(xadj, adjncy, lst[i], mate, flag, level, maxlevel);
|
|
}
|
|
|
|
MinCover_Decompose(xadj, adjncy, asize, bsize, mate, cover, csize);
|
|
|
|
gk_free((void **)&mate, &flag, &level, &queue, &lst, LTERM);
|
|
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* This function performs a restricted DFS and augments matchings
|
|
**************************************************************************/
|
|
idx_t MinCover_Augment(idx_t *xadj, idx_t *adjncy, idx_t col, idx_t *mate, idx_t *flag, idx_t *level, idx_t maxlevel)
|
|
{
|
|
idx_t i;
|
|
idx_t row = -1;
|
|
idx_t status;
|
|
|
|
flag[col] = 2;
|
|
for (i=xadj[col]; i<xadj[col+1]; i++) {
|
|
row = adjncy[i];
|
|
|
|
if (flag[row] == 1) { /* First time through this row node */
|
|
if (level[row] == maxlevel) { /* (col, row) is an edge of the G^T */
|
|
flag[row] = 2; /* Mark this node as being visited */
|
|
if (maxlevel != 0)
|
|
status = MinCover_Augment(xadj, adjncy, mate[row], mate, flag, level, maxlevel-1);
|
|
else
|
|
status = 1;
|
|
|
|
if (status) {
|
|
mate[col] = row;
|
|
mate[row] = col;
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
|
|
/*************************************************************************
|
|
* This function performs a coarse decomposition and determines the
|
|
* min-cover.
|
|
* REF: Pothen ACMTrans. on Amth Software
|
|
**************************************************************************/
|
|
void MinCover_Decompose(idx_t *xadj, idx_t *adjncy, idx_t asize, idx_t bsize, idx_t *mate, idx_t *cover, idx_t *csize)
|
|
{
|
|
idx_t i, k;
|
|
idx_t *where;
|
|
idx_t card[10];
|
|
|
|
where = imalloc(bsize, "MinCover_Decompose: where");
|
|
for (i=0; i<10; i++)
|
|
card[i] = 0;
|
|
|
|
for (i=0; i<asize; i++)
|
|
where[i] = SC;
|
|
for (; i<bsize; i++)
|
|
where[i] = SR;
|
|
|
|
for (i=0; i<asize; i++)
|
|
if (mate[i] == -1)
|
|
MinCover_ColDFS(xadj, adjncy, i, mate, where, INCOL);
|
|
for (; i<bsize; i++)
|
|
if (mate[i] == -1)
|
|
MinCover_RowDFS(xadj, adjncy, i, mate, where, INROW);
|
|
|
|
for (i=0; i<bsize; i++)
|
|
card[where[i]]++;
|
|
|
|
k = 0;
|
|
if (iabs(card[VC]+card[SC]-card[HR]) < iabs(card[VC]-card[SR]-card[HR])) { /* S = VC+SC+HR */
|
|
/* printf("%"PRIDX" %"PRIDX" ",vc+sc, hr); */
|
|
for (i=0; i<bsize; i++)
|
|
if (where[i] == VC || where[i] == SC || where[i] == HR)
|
|
cover[k++] = i;
|
|
}
|
|
else { /* S = VC+SR+HR */
|
|
/* printf("%"PRIDX" %"PRIDX" ",vc, hr+sr); */
|
|
for (i=0; i<bsize; i++)
|
|
if (where[i] == VC || where[i] == SR || where[i] == HR)
|
|
cover[k++] = i;
|
|
}
|
|
|
|
*csize = k;
|
|
gk_free((void **)&where, LTERM);
|
|
|
|
}
|
|
|
|
|
|
/*************************************************************************
|
|
* This function performs a dfs starting from an unmatched col node
|
|
* forming alternate paths
|
|
**************************************************************************/
|
|
void MinCover_ColDFS(idx_t *xadj, idx_t *adjncy, idx_t root, idx_t *mate, idx_t *where, idx_t flag)
|
|
{
|
|
idx_t i;
|
|
|
|
if (flag == INCOL) {
|
|
if (where[root] == HC)
|
|
return;
|
|
where[root] = HC;
|
|
for (i=xadj[root]; i<xadj[root+1]; i++)
|
|
MinCover_ColDFS(xadj, adjncy, adjncy[i], mate, where, INROW);
|
|
}
|
|
else {
|
|
if (where[root] == HR)
|
|
return;
|
|
where[root] = HR;
|
|
if (mate[root] != -1)
|
|
MinCover_ColDFS(xadj, adjncy, mate[root], mate, where, INCOL);
|
|
}
|
|
|
|
}
|
|
|
|
/*************************************************************************
|
|
* This function performs a dfs starting from an unmatched col node
|
|
* forming alternate paths
|
|
**************************************************************************/
|
|
void MinCover_RowDFS(idx_t *xadj, idx_t *adjncy, idx_t root, idx_t *mate, idx_t *where, idx_t flag)
|
|
{
|
|
idx_t i;
|
|
|
|
if (flag == INROW) {
|
|
if (where[root] == VR)
|
|
return;
|
|
where[root] = VR;
|
|
for (i=xadj[root]; i<xadj[root+1]; i++)
|
|
MinCover_RowDFS(xadj, adjncy, adjncy[i], mate, where, INCOL);
|
|
}
|
|
else {
|
|
if (where[root] == VC)
|
|
return;
|
|
where[root] = VC;
|
|
if (mate[root] != -1)
|
|
MinCover_RowDFS(xadj, adjncy, mate[root], mate, where, INROW);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|