分支限界——最大团问题
问题:
最大团问题。
分析:
类似装载问题,01子集树,上界为剩下所有未被选择的点全算上。
代码:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 105
#define INF 0x3f3f3f
int m[MAXN][MAXN];
int bestN = 0;
struct Node{
int level;
int cn;
int upbound;
Node* parent;
int isLeft;
Node(int _level,int _cn,int _upbound,Node* _parent,int _isLeft){
level = _level;
cn = _cn;
upbound = _upbound;
parent = _parent;
isLeft = _isLeft;
}
};
struct cmp{
bool operator()(Node* n1,Node* n2){
return n1->upbound < n2->upbound;// 这是大顶堆
}
};
priority_queue<Node*,vector<Node*>,cmp> pq;
bool constrain(Node* cNode){
int tmp[MAXN];
int n = cNode->level;
tmp[n] = 1;
while(cNode->parent!=NULL){
tmp[cNode->level-1] = cNode->isLeft?1:0;
cNode = cNode->parent;
}
for(int i = 1;i <= n;i++){
if(tmp[i]){
for(int j = 1;j <= n;j++){
if(i == j) continue;
if(tmp[j] && !m[i][j]) return false;
}
}
}
return true;
}
void maxGroupPrior(int n){
// 初始化
Node* root = new Node(1,0,n,NULL,false);
pq.push(root);
Node* bestNode = NULL;
// 开始广搜
while(!pq.empty()){
// 队首
Node* cNode = pq.top();
pq.pop();
if(cNode->level==n+1){
bestN = cNode->cn;
bestNode = cNode;
break;
}
// 左判约束
if(constrain(cNode)){
// 新建可行节点
Node* tmp1 = new Node(cNode->level+1,cNode->cn+1,n-cNode->level+cNode->cn+1,cNode,true);
if(cNode->cn+1 > bestN){
bestN = cNode->cn+1;
bestNode = tmp1;
}
// 将该节点加入优先队列
pq.push(tmp1);
}
// 右判界
if(cNode->upbound > bestN){
// 新建可行节点
Node* tmp2 = new Node(cNode->level+1,cNode->cn,n-cNode->level+cNode->cn,cNode,false);
if(cNode->cn > bestN){
bestN = cNode->cn;
bestNode = tmp2;
}
// 将该节点加入优先队列
pq.push(tmp2);
}
}
// 输出最优解
cout<<bestN<<endl;
while(bestNode->parent!=NULL){
if(bestNode->isLeft){
cout<<1<<" ";
}else{
cout<<0<<" ";
}
bestNode = bestNode->parent;
}
}
int main(){
int n = 5;
memset(m, 0, sizeof(m));
m[1][2] = 1;
m[1][4] = 1;
m[1][5] = 1;
m[2][3] = 1;
m[2][5] = 1;
m[3][5] = 1;
m[4][5] = 1;
m[2][1] = 1;
m[4][1] = 1;
m[5][1] = 1;
m[3][2] = 1;
m[5][2] = 1;
m[5][3] = 1;
m[5][4] = 1;
maxGroupPrior(n);
}
注意几个修正的点:
- 当叶节点也加入优先队列时,遇到的第一个叶节点就是最优值,因为以极大化问题为例,扩展节点的上界一定小于其父节点的上界,因为其理想化程度降低,有更多考虑已选节点的内容,而叶节点全部是已选内容,就是真实值,若优先队列的队首元素是叶节点,那优先队列里面其他的节点所到达的叶节点的值一定都小于这个叶节点,换句话说这个叶节点一定是最优值,可以break。
- 优先队列n1>n2是小顶堆!!!!太坑了,前面一直没注意,de了好多次bug最后还放弃了加入叶节点。