无向图的最大割问题的实现
2015-05-07 23:57
148 查看
问题描述:
什么是无向图的最大割?
有无向图G=(V,E).设U是V的一个子集。对任意的顶点u,v如果(u,v)是E中的一条边,如果u在U中,则v一定不
在U中,这样的边称为顶点集合U的一个割边。那个这个顶点集合U所有的割边就构成图G的一个割。最大割
的意思,就是说含割边最多的割。
编程任务:
给定一个无向图G,计算G的最大割。
数据输入:
第一行2个整数 n,e表示顶点个数和边个数。下面e行是边,每行2个整数对应顶点编号。顶点编号从1-n;
数据输出:
第一行是最大割的边数。
第二行是顶点集的向量对应1-n,0表示不在集合,1表示在集合。
解题思想:
这道题也是一个子集选取问题,所以它的解空间树是一个子集树。这个集合n个元素,每个元素可以有
选取或不选取2种选择,所以共用2^n个子集。
这里用分支界限法。
分支界限法:类似宽度优先搜索,它和回溯的区别在与,它每次都取一个节点,然后把它的所有的儿子节点
都扩展,然后加到队列中,所以说,分支界限法,这种扩展方式导致没个节点最多一次扩展机会,它在扩展
它的分支的时候,根据一定的界限条件,或淘汰不可能产生最优解的分支。
这里的队列有2种,一种是普通队列就是先进先出。
另一种就是优先级队列,它会根据优先级进行出队,这和Windows中的消息队列类似。
在C++中,STL中priority_queue就是优先级队列。queue是普通队列。优先级队列可以用最大堆或最小堆
实现。
#include <iostream>
#include <queue>
using namespace std;
int n,e;//顶点数和边数
int Graph[200][200];//存储图的邻接矩阵
int bestcut = 0;//存储最优解
int bestx[200];//存储最优解
struct HeapNode//队列节点
{
HeapNode()
{
memset(x,0,sizeof(x));
}
int i;
int cut;
int edges;
int x[200];
booloperator < (const HeapNode&a)const
{
returncut<a.cut;
}
};
void maxcut()
{
HeapNodeE;
priority_queue<HeapNode> Q;
E.cut = 0;
E.edges = e;
E.i = 0;
while (1)
{
if (E.i==n)
{
if (E.cut>bestcut)
{
bestcut = E.cut;
memcpy(bestx,E.x,sizeof(int)*n);
}
}
else
{
HeapNodetemp = E;
int i =E.i;
for (intj=0;j<n;j++)
{
if (Graph[i][j])
{
if (temp.x[j])
{
temp.cut--;
}
else
{
temp.cut++;
temp.edges--;
}
}
}
temp.x[i] =1;
temp.i++;
Q.push(temp);
if(E.cut+E.edges>bestcut)//界限条件
{
E.i++;
Q.push(E);
}
}
if(Q.size()==0)//队列为空跳出循环
{
break;
}
E = Q.top();
Q.pop();
}
}
int main()
{
intu,v;
cin>>n>>e;
for (int i=0;i<e;i++)
{
cin>>u>>v;
Graph[u-1][v-1] = 1;
Graph[v-1][u-1] = 1;
}
maxcut();
cout<<bestcut<<endl;
for (int k=0;k<n;k++)
{
cout<<bestx[k]<<'';
}
cout<<endl;
return 0;
}
输入实例
7 18
1 4
1 5
1 6
1 7
2 3
2 4
2 5
2 6
2 7
3 4
3 5
3 6
3 7
4 5
4 6
5 6
5 7
6 7
输出实例:
12
1 1 1 0 1 0 0
什么是无向图的最大割?
有无向图G=(V,E).设U是V的一个子集。对任意的顶点u,v如果(u,v)是E中的一条边,如果u在U中,则v一定不
在U中,这样的边称为顶点集合U的一个割边。那个这个顶点集合U所有的割边就构成图G的一个割。最大割
的意思,就是说含割边最多的割。
编程任务:
给定一个无向图G,计算G的最大割。
数据输入:
第一行2个整数 n,e表示顶点个数和边个数。下面e行是边,每行2个整数对应顶点编号。顶点编号从1-n;
数据输出:
第一行是最大割的边数。
第二行是顶点集的向量对应1-n,0表示不在集合,1表示在集合。
解题思想:
这道题也是一个子集选取问题,所以它的解空间树是一个子集树。这个集合n个元素,每个元素可以有
选取或不选取2种选择,所以共用2^n个子集。
这里用分支界限法。
分支界限法:类似宽度优先搜索,它和回溯的区别在与,它每次都取一个节点,然后把它的所有的儿子节点
都扩展,然后加到队列中,所以说,分支界限法,这种扩展方式导致没个节点最多一次扩展机会,它在扩展
它的分支的时候,根据一定的界限条件,或淘汰不可能产生最优解的分支。
这里的队列有2种,一种是普通队列就是先进先出。
另一种就是优先级队列,它会根据优先级进行出队,这和Windows中的消息队列类似。
在C++中,STL中priority_queue就是优先级队列。queue是普通队列。优先级队列可以用最大堆或最小堆
实现。
#include <iostream>
#include <queue>
using namespace std;
int n,e;//顶点数和边数
int Graph[200][200];//存储图的邻接矩阵
int bestcut = 0;//存储最优解
int bestx[200];//存储最优解
struct HeapNode//队列节点
{
HeapNode()
{
memset(x,0,sizeof(x));
}
int i;
int cut;
int edges;
int x[200];
booloperator < (const HeapNode&a)const
{
returncut<a.cut;
}
};
void maxcut()
{
HeapNodeE;
priority_queue<HeapNode> Q;
E.cut = 0;
E.edges = e;
E.i = 0;
while (1)
{
if (E.i==n)
{
if (E.cut>bestcut)
{
bestcut = E.cut;
memcpy(bestx,E.x,sizeof(int)*n);
}
}
else
{
HeapNodetemp = E;
int i =E.i;
for (intj=0;j<n;j++)
{
if (Graph[i][j])
{
if (temp.x[j])
{
temp.cut--;
}
else
{
temp.cut++;
temp.edges--;
}
}
}
temp.x[i] =1;
temp.i++;
Q.push(temp);
if(E.cut+E.edges>bestcut)//界限条件
{
E.i++;
Q.push(E);
}
}
if(Q.size()==0)//队列为空跳出循环
{
break;
}
E = Q.top();
Q.pop();
}
}
int main()
{
intu,v;
cin>>n>>e;
for (int i=0;i<e;i++)
{
cin>>u>>v;
Graph[u-1][v-1] = 1;
Graph[v-1][u-1] = 1;
}
maxcut();
cout<<bestcut<<endl;
for (int k=0;k<n;k++)
{
cout<<bestx[k]<<'';
}
cout<<endl;
return 0;
}
输入实例
7 18
1 4
1 5
1 6
1 7
2 3
2 4
2 5
2 6
2 7
3 4
3 5
3 6
3 7
4 5
4 6
5 6
5 7
6 7
输出实例:
12
1 1 1 0 1 0 0
相关文章推荐
- TOP N的一些问题,可以实现取得表中最大的一行ID的数据。
- TOP N的一些问题,可以实现取得表中最大的一行ID的数据。
- 最大连续邮资问题的JAVA实现
- 一个无聊男人的疯狂《数据结构与算法分析-C++描述》学习笔记 用C++/lua/python/bash的四重实现(3) 最大子序列和问题
- 用动态规划算法对最大子串问题的java实现
- 三种算法求最大子段和问题——Java实现
- TSP问题之最大最小蚁群算法cpp实现
- 最大子段和问题的分治实现和动态实现
- 连续子向量的最大和问题(Python实现)
- 寻找最大的k个数,TopK问题的C++实现
- 寻找最大的K个数,Top K问题的堆实现
- Python实现最大子树问题
- 数字问题之最大公约数问题全解法归纳<Java实现>
- 数组问题之一维最大字段和问题<Java实现>
- 三种算法实现最大子段和问题(Java实现)
- 最大团问题实例--部落卫队问题实现
- 算法设计与分析--求最大子段和问题(蛮力法、分治法、动态规划法) C++实现
- 算法设计与分析--求最大子段和问题(蛮力法、分治法、动态规划法) C++实现
- 一维数组及子数组最大和问题Java实现
- 算法导论C语言实现: 分治策略 -- 最大子数组问题