算法分析实验,写的有点乱,保存备用,同时供大家参考,写的不是很好,如有问题可提出交流和修改!
#include<iostream>
#include<vector>
#include<set>
using namespace std;
static int temp = 0;//在找圈方法中用于圈个数的计数
class Circle
{
public:
Circle()
{
this->vertexNum = 0;
this->circleWeight = 0;
vertex = new pair<int, int>[10];
circleEdge.resize(10);
}
int getCircleWeight() //计算并返回圈的权
{
for (int i = 0; i < vertexNum; i++)
{
circleWeight += circleEdge[i];
}
return circleWeight;
}
public:
int vertexNum; //圈的顶点数
vector<int> circleEdge; //二维数组存储边的权
int circleWeight; //圈的权值
pair<int, int> *vertex; //存储圈的边的坐标
};
class MatrixGraphic
{
public:
MatrixGraphic()
{
this->vertexNum = 0;
this->edgeNum = 0;
this->graphicWeight = 0;
this->circleNum = 0;
}
MatrixGraphic(int verNumber, int edgNumber)
{
circle = new Circle[10];
vector<vector<int>> a(verNumber);
this->vertexNum = verNumber;
this->edgeNum = edgNumber;
mixCircleNum = (edgeNum + 1) - vertexNum;
edge = a;
for (int i = 0; i <vertexNum; i++)
edge[i].resize(vertexNum); //初始化邻接矩阵的大小
}
/*输入整个图*/
void cinGraphic();
/*找出所有圈并对其按照权的大小进行升序排序*/
void fundCircle(int num1, int num2,int num3,vector<pair<int,int> > b);
/*是否能组成圈*/
bool isCircle(int num,vector<pair<int, int> > b);
/*找最小圈基*/
int fundMinCircle();
/*判断一个圈是否是圈基中的线性组合*/
//void isCombin(int n);
/*是否停止向圈基中继续加圈*/
//bool isStop(int n);
public:
int vertexNum; //图的顶点数
int edgeNum; //图的边数
int graphicWeight; //图的权值
vector<vector<int>> edge; //二维数组存储边的权
pair<int,int> vertex[20]; //存储边的坐标
Circle* circle; //图中各圈
int circleNum; //计数器,计算圈的个数
int mixCircleNum; //最小圈基的范围
};
void MatrixGraphic::cinGraphic()
{
int num = 0;
cout << "请以"<< vertexNum <<"*"<< vertexNum <<"的邻接矩阵的形式输入图:" << endl;
for (int i = 0; i < vertexNum; i++)
for (int j = 0; j < vertexNum; j++)
{
int n;
cin >> n;
edge[i][j] = n;
}
/*存储图的边的坐标*/
for (int i = 0; i < vertexNum; i++)
for (int j = i; j < vertexNum; j++)
{
if (edge[i][j] != 0)
{
vertex[num].first = i;
vertex[num].second = j;
num++;
}
}
}
/*用组合算法找出n个顶点的所有组合(不考虑位置)
num1为图的顶点个数,num2为组合的顶点个数,b为所有组合构成的集合
*/
void MatrixGraphic::fundCircle(int num1, int num2,int num3, vector<pair<int,int> > b)
{
for (int i = num1; i >= num2; i--)
{
/*找出组合*/
b[num2 - 1] = vertex[i - 1];
if (num2 > 1)
{
fundCircle(i - 1, num2 - 1, num3, b);
}
else
{
/*如果组合能构成圈,将其放到circle中*/
if (isCircle(num3, b))
{
for (int i = b.size() - 1; i >= 0; i--)
{
circle[temp].vertex[i] = b[i]; //将顶点赋值给对应的圈的顶点
circle[temp].circleEdge[i] = edge[b[i].first][b[i].second];
}
circleNum += 1;
circle[temp].vertexNum = b.size();
++temp;
}
}
}
}
/*判断是否构成圈思路:
(1)n条边能组合成圈的顶点只有n个
(2)所有边的坐标点的集合都是成对出现的,如(01 03 12 23中0 1 2 3都是成对出现的)
(3)
*/
bool MatrixGraphic::isCircle(int num, vector<pair<int, int> > b)
{
vector<int> ver;
set<int>s0;
set<int>s1;
set<int>s2;
int n = 0;
for (int i = 0; i < b.size(); i++)
{
s0.insert(b[i].first);
}
for (int i = 0; i < b.size(); i++)
{
s1.insert(b[i].second);
}
for (int i = 0; i < b.size(); i++)
{
ver.push_back(b[i].first);
ver.push_back(b[i].second);
s2.insert(b[i].first);
s2.insert(b[i].second);
}
/*n条边能组合成圈的顶点只有n个,且都是成对出现的(有且只有两个)*/
for (int i = 0; i < b.size() * 2; i++)
{
for (int j = 0; j < b.size() * 2; j++)
{
if (ver[i] == ver[j])
n += 1;
}
if (n > 2)
return false;
else
{
n = 0;
}
}
if (s2.size() == num && s0.size() == (num - 1) && s1.size() == (num - 1) )
return true;
else
return false;
}
/*找最小圈基的思路:
对排好序的圈挨个放进圈基,如果圈是圈基的线性组合(即圈的所有边在圈基中都可以找到),删掉
直到圈基中圈的个数满足要求停止加圈
*/
int MatrixGraphic::fundMinCircle()
{
static int temp1 = 2;
int minCircle = 0; //最小圈基的权
set<pair<int,int> >MySet;
Circle *Mycircle = new Circle[mixCircleNum];
for (int i = 0; i < circleNum; i++)
{
if (i < 2)
{
Mycircle[i] = circle[i];
}
else
{
/*先把所有的边放到集合set中*/
for (int a = 0; a < i; a++)
{
for (int b = 0; b < circle[a].vertexNum; b++)
{
MySet.insert(Mycircle[a].vertex[b]);
}
}
temp = 0;
for (int j = 0; j < circle[i].vertexNum; j++)//检验第i是否是组合成的,分别扫描它的所有顶点
{
if (MySet.find(circle[i].vertex[j])!=MySet.end())
{
temp += 1;
}
}
if (temp != circle[i].vertexNum)
{
Mycircle[temp1] = circle[i];
temp1++;
}
if (temp1 == (mixCircleNum))
break;
MySet.clear();
}
}
for (int i = 0; i < mixCircleNum; i++)
{
minCircle += Mycircle[i].circleWeight;
}
/*输出最小圈基*/
cout <<endl<< "最小圈基:" << endl;
for (int i = 0; i < mixCircleNum; i++)
{
for (int j = 0; j < Mycircle[i].vertexNum; j++)
{
cout << Mycircle[i].vertex[j].first << Mycircle[i].vertex[j].second << " ";
}
cout << endl;
}
return minCircle;
}
int main()
{
int e, v; //存储图的顶点和边
cout << "请输入图的顶点和边数:" << endl;
cin >> e >> v;
MatrixGraphic MyGraphic(e,v); //定义一个图对象
MyGraphic.cinGraphic(); //调用cinGraphic()方法,以邻接矩阵的形式输入整个图
//找到所有的圈
/*找圈的思路:
(1)3个或3个以上的顶点可构成圈,找出可以构成圈的所有可能的顶点组合
(2)从找出的组合中再筛选出真正能构成圈的
*/
for (int i = 3; i <= v; i++)
{
vector<pair<int, int> > b(i);
MyGraphic.fundCircle(v, i,i, b);//fundCircle方法用到了排列组合
}
cout << "输出图中所有圈的权:" << endl;
for (int i = 0; i < MyGraphic.circleNum; i++)
{
MyGraphic.circle[i].getCircleWeight(); //计算圈的权
cout << MyGraphic.circle[i].circleWeight << " ";
}
/*对所有圈按照升序排列*/
Circle MyCircl;
for (int i = 0; i < MyGraphic.circleNum - 1; i++)
{
for (int j = i+1; j < MyGraphic.circleNum ; j++)
if (MyGraphic.circle[i].circleWeight > MyGraphic.circle[j].circleWeight)
{
MyCircl = MyGraphic.circle[i];
MyGraphic.circle[i] = MyGraphic.circle[j];
MyGraphic.circle[j] = MyCircl;
}
}
cout << endl;
cout << "排序后的圈的权:" << endl;
for (int i = 0; i < MyGraphic.circleNum; i++)
{
//MyGraphic.circle[i].getCircleWeight();
cout << MyGraphic.circle[i].circleWeight << " ";
}
cout<<endl<<"最小圈基的权:"<<MyGraphic.fundMinCircle()<<endl;//调用fundMinCircle()方法,输出最小圈基和它的权
return 0;
}