无向图的最大割问题(分支限界)

问题描述

给定一个无向图G=(V, E),设U\subseteq V是G的顶点集。对任意(u, v)∈E,若u∈U,且v∈V-U,就称(u, 1)为关于顶点集U的一条割边。顶点集U的所有割边构成图G的一个割。G的最大割是指G中所含边数最多的割。

对于给定的无向图G,设计一个优先队列式分支限界法,计算G的最大割。

分析

  • 解向量:(x1,x2,……xn)是一个01序列,其中xi=1表示点xi在割集,0表示不在割集
  • 解空间:完全二叉树,子集树
  • 用node类来表示节点,每个节点含有的元素:当前层 割边数量 剩余边的数量 解向量
  • 优先级:每个节点当前割边数量
  • 如果还没有到叶节点:
    左子节点直接加入优先队列。修改解向量,该左子节点加入后修改割边数量和剩余边数量
    右子节点需要判断是否需要剪枝:当前割边数+剩余边数>当前最优解时,加入队列。修改解向量,该右子节点加入后修改剩余边数量
  • 到达叶节点,即求得最优值

代码

#include <bits/stdc++.h>
#include <fstream>
#include <iostream> 
using namespace std;
 
const int MAX = 1000;
int G[MAX][MAX];//存储边信息 
int bestx[MAX];//最优值的割集 
int w[MAX];//顶点的权
int n, e; //顶点数,边数 
ifstream in("input.txt");
ofstream out("output.txt"); 
 
//结点类 
class Node
{
public:
    int dep;  //当前层
    int cut;  //割边数量
    int e;    //剩余边的数量
    int *x;   //解向量
 
    Node(int d, int c, int ee)
    {
        x = new int[n+1];
        dep = d;
        cut = c;
        e = ee;
    }
 
    //割边数大的先出队列
    bool operator<(const Node &node) const
    {
        return cut < node.cut;
    }
};
 
//存储待解决的结点的优先队列 
priority_queue<Node> q;
 
//添加结点
void addNode(Node enode, bool isLeft)
{
    Node now(enode.dep+1,enode.cut,enode.e);
    copy(enode.x, enode.x+n+1, now.x);
    //是左结点 
    if(isLeft)
    {
        now.x[now.dep] = 1;//因为是左节点 标记是割集元素 
        for(int j=1;j<=n;j++)//统计割边的增量 
            if(G[now.dep][j])
                if(now.x[j] == 0) //如果当前顶点在割集中,但边的另一个顶点不在割集
                {
                    now.cut++;  //割边的数量增加
                    now.e--;    //剩余边的数量减少
                }
                else
                    now.cut--;//否则割边数量减少 
    }
    else//右节点 
    { 
        now.x[now.dep] = 0;//标记不是割集元素 
        now.e--;//剩余边的数量减少
    }
    q.push(now);//加入优先队列 
}
 
int search()
{
	//初始化 :层0 割边0 剩余边e 
    Node enode(0, 0, e);
    for(int j=1; j<=n; j++)
        enode.x[j] = 0;//解向量 
    int best = 0;
    //分支限界求解 
    while(true)
    {
        if(enode.dep>n)//到达叶子节点,如果比当前最优解更优,更新 
        {
            if(enode.cut>best)
            {
                best = enode.cut;
                copy(enode.x, enode.x+n+1, bestx);
                break;
            }
        }
        else//没有到达叶子节点 
        {
            addNode(enode,true);//加入左子结点 
            if(enode.cut+enode.e>best)//满足约束条件,加入右子结点 
                addNode(enode,false);
        }
        if(q.empty())
            break;
        else//取出队首元素 
        {
            enode = q.top();
            q.pop(); 
        }
    }
    return best;
}
 
int main()
{
	int a, b, i;
    in>>n>>e;    
    memset(G, 0, sizeof(G));
    for(i=1; i<=e; i++)
    {
        in >> a >> b;
        G[a][b] = G[b][a] = 1;
    }
    out << search()<<'\n';
    for(i=1; i<=n; i++){
    	out << bestx[i];
    	if(i!=n) out<<" ";
	}
    out<<'\n';   
    in.close();
    out.close();
    return 0;

} 

时间复杂度

  • 时间复杂度:最坏情况下要遍历整棵树,O(2^n)
  • 空间复杂度:最坏情况下要保存最后一层的所有结点,每个结点要记录当前的解,O(n*2^n)
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是最大问题分支限界算法的伪代码: ``` maxClique(G): bestClique = [] clique = [] nodes = G.nodes() sortedNodes = sortNodesByDegree(nodes, G) expandCliques(clique, sortedNodes, G, bestClique) return bestClique expandCliques(clique, sortedNodes, G, bestClique): if no nodes left to add: if len(clique) > len(bestClique): bestClique = clique return if len(clique) + len(sortedNodes) <= len(bestClique): return node = sortedNodes.pop(0) expandCliques(clique + [node], getNextNodes(node, sortedNodes, G), G, bestClique) expandCliques(clique, sortedNodes, G, bestClique) getNextNodes(node, sortedNodes, G): return [n for n in sortedNodes if G.has_edge(node, n)] sortNodesByDegree(nodes, G): return sorted(nodes, key=lambda x: G.degree[x], reverse=True) ``` 其中,`maxClique` 函数接收一个无向图 `G` 作为输入,返回最大团。该函数首先初始化 `bestClique` 和 `clique` 两个空列表,分别代表当前最优解和当前搜索路径中的节点。然后,按照节点度数从大到小排序,调用 `expandCliques` 函数进行搜索,并返回 `bestClique`。 `expandCliques` 函数接收当前搜索路径中的节点列表 `clique`、按度数排序后的节点列表 `sortedNodes`、无向图 `G` 和当前最优解 `bestClique`。如果当前节点列表中已经没有可以添加的节点,则判断是否是最优解,并返回。如果添加当前节点后的团大小不足以超过当前最优解,则剪枝。否则,将当前节点添加到搜索路径中,更新 `sortedNodes` 列表,继续搜索。然后,回溯到上一层搜索。 `getNextNodes` 函数接收当前节点和按度数排序后的节点列表 `sortedNodes`、无向图 `G`,返回与当前节点相邻且尚未添加到搜索路径中的节点。 `sortNodesByDegree` 函数按照节点度数从大到小排序,并返回排序后的节点列表。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值