在图形上执行边缘收缩

时间:2010-07-03 22:08:54

标签: c++ algorithm data-structures graph

我试图在图表上进行边缘收缩。 n是图中顶点的数量。 包含表示边的顶点对的向量f包含要收缩的边。

图表不包含任何自循环。

如果代码中有任何逻辑错误,请指出。 如果方法完全错误,请告诉我正确的算法。

void modify(vector<pair<int, int> > &f)
{
    // sorting elements of each pair
    for(vector<pair<int, int> >::iterator it = f.begin(); it != f.end(); it++)
    {
      if(it->first > it->second)
        swap(it->first, it->second);
    }

    // sorting elements of set f
    sort(f.begin(), f.end());
    reverse(f.begin(), f.end());

    for(vector<pair<int, int> >::iterator it = f.begin(); it != f.end(); it++)
    {
      int x, y;
      x = it->first;
      y = it->second;

      for(int i = 0; i < n; i++)
        if(x != i)
        {
          graph[x][i] = graph[y][i] = graph[x][i] + graph[y][i];
          graph[i][x] = graph[i][y] = graph[i][x] + graph[i][y];
        }
    }


    vector<bool> pos(n, false); // array of positions to be deleted

    for(vector<pair<int, int> >::iterator it = f.begin(); it != f.end(); it++)
      pos[it->second] = true;

    // deleting rows
    int count = 0;
    for(int i = 0; i < n; i++)
    {
            for(int j = 0; j < n; j++)
              graph[i-count][j] = graph[i][j];
            if(pos[i])
              count++;
    }

    // deleting columns
    count = 0;
    for(int j = 0; j < n; j++)
    {
            for(int i = 0; i < n; i++)
              graph[i][j-count] = graph[i][j];
            if(pos[j])
              count++;
    }

    // finally dimension of the matrix becomes n - count
    n = n - count;
}

提前致谢。

2 个答案:

答案 0 :(得分:3)

给出以下示例图:

a       d
 \     /
  b---e
 /     \
c       f

“收缩”边缘{b,e}会导致以下结果吗?:

a   d
 \ /
  g
 / \
c   f

“是的,就是这样” - amit。谢谢,在我回答你的问题之前,我想让规范正确。进一步的假设是:

  • 图表指示
  • 顶点用整数表示。
  • 图表存储在二维数组graph中,graph[x][y]是边(x,y)的权重; 0表示没有从x到y的边缘

让我们尝试一下伪代码

void contractEdge(int v1, int v2) {
    for (int i = 0; i < n; i++) {
        if (graph[v2][i] > 0) {
            graph[v1][i] = graph[v1][i] > 0 ? min(graph[v1][i], graph[v2][i]) :
                                              graph[v2][i];
            graph[v2][i] = 0;
        }
        if (graph[i][v2] > 0) {
            graph[i][v1] = graph[i][v1] > 0 ? min(graph[i][v1], graph[i][v2]) :
                                              graph[i][v2];
            graph[i][v2] = 0;
        }
        graph[v1][v2] = graph[v2][v1] = 0;
    }
}

代码的工作方式如下:给定边{v1,v2},v1成为“收缩”顶点。这意味着,不是插入一个新的顶点(在我的第一个例子中为“g”),v1保留在图形中并从中删除v2(通过在边缘上为所有其他顶点指定0权重,实际顶点计数不会改变)。此外,包含v2的所有边都弯曲以包含v1。

现在可以为一组边调用此方法。运行时将为O(n * #edges_to_contract)。我希望这是你想要的行为。

重要事项:如果您对边权重使用不同的表示,即0表示边缘的权重为0而∞(无限)表示没有边缘,那么您的问题变得微不足道,因为所有你要做的是:

graph[v1][v2] = graph[v2][v1] = 0

有效收缩边缘{v1,v2},因为现在在v1和v2之间旅行不需要任何费用

答案 1 :(得分:2)

这不是边收缩,而是顶点收缩。当然,连接收缩顶点的边缘消失,连接原始顶点与其邻居的边缘的权重必须相加。