问题陈述:给定一个连通图G=(V,E),如下图所示,求它的连通性图。
算法:
输入:一个连通图G=(V,E)
输出:输出G的连通性图Gc=(V,E,sc(u,v))
k=1;
while(求解k边连通分量非空)do
求解k边连通分量,将其内包含的边的权值改为k;
k=k+1;
end while;
输入输出用到的图我都是用邻接矩阵也就是一个二维数组来存储的。
因为我毕设要做的算法是在属性图上的,所以展示的图是带有属性的,大家看的时候把属性忽略就好啦。
代码如下所示:
#include<cstdio>
#include<cstring>
#include<queue>
#include<iostream>
#include <algorithm>
using namespace std;
const int INF = 1000000;
const int N = 110;
int side[N][N];
int sc[N][N];
int grid[N][N];
int w[N];
bool vis[N];
bool deleted[N];
bool choose[N];
int K;
//定义了两个队列qa,qb
queue<int>qa,qb;
//定义了两个向量qc和qd用来记录属性得分最大的图内包含的节点
vector<int>qc,qd;
vector<int>VQuery;
vector<char>AQuery;
vector<char>attribute[14];
int pointsum1=0; //qc的得分
int pointsum2=0;//qd的得分
vector<int>nodes[N];
//设查询节点为1,6,查询属性集为{music,art}
//prim算法求两点之间的最小割
int prim(int k,int n,int &s,int &t){ //求k和n点之间的最小割
s=0; //s=0 第0个顶点
while(deleted[s])s++; //若deleted[s]=True时候,s++
for(int i=0;i<n;i++){ //遍历n次
w[i]=grid[s][i]; //w记录了与s点相连的点
vis[i]=false; //vis中的n个元素全部为false
}
vis[s]=true; //第s个 顶点位置置为true
int p; //定义一个顶点p,一个最大值Max
int Max;
for(int i=1;i<k;i++){
Max=-INF; //Max=-INF
for(int j=0;j<n;j++) //遍历n次
if(!vis[j]&&!deleted[j]){ //vis【j】假且deleted【j】假
if(w[j]>Max){ //如果w【j】>Max
Max=w[j]; //则Max=W【j】
p=j; //p=j
}
}
if(i==k-2)s=p;
if(i==k-1)t=p;
vis[p]=true;
for(int i=0;i<n;i++) //遍历n次
if(!vis[i]&&!deleted[i]){ //vis【j】假且deleted【j】假
w[i]+=grid[i][p]; //w[i]=w[i]+grid[i][p]
}
}
return w[t]; //w[t]记录了最小割
}
//求全局最小割
int stoerwagner(int n){
if(n<=1)return 0; //如果节点数小于等于1,则返回0
int min_cut=INF,s,t; //
for(int i=0;i<n;i++){ //将deleted全赋值为false,nodes={0,1,2,3,4}
deleted[i]=false;
nodes[i].clear();
nodes[i].push_back(i);
}
for(int i=1;i<n;i++){ // 遍历n-1次就可以找到全局最小割了
int cut=prim(n-i+1,n,s,t); // 求割边cut是prim(n-i+1,n,s,t)
if(cut<min_cut){
min_cut=cut;
for(int j=0;j<n;j++)
choose[j]=0;
for(int j=0;j<nodes[t].size();j++)
choose[nodes[t][j]]=1;
}
for(int i=0;i<nodes[t].size();i++){
nodes[s].push_back(nodes[t][i]);
}
deleted[t]=true;
for(int i=0;i<n;i++){
if(i==s)continue;
if(!deleted[i]){
grid[s][i]+=grid[t][i];
grid[i][s]+=grid[i][t];
}
}
}
for(int i=0;i<n;i++){
if(choose[i])qa.push(i); //把节点集合分成两部分
else qb.push(i);
}
return min_cut;
}
//solve递归解决问题 求连通度图
int solve(vector<int> a){
int n=a.size();
if(n<=1)return 1; //如果节点个数小于等于1则返回1
int t;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
grid[i][j]=side[a[i]][a[j]]; // 将side赋值给grid
}
if(stoerwagner(n)==K){
//求连通度图
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
sc[a[i]][a[j]]=side[a[i]][a[j]]*K;
}
while(!qa.empty())qa.pop(); // 若qa非空,qa出队
while(!qb.empty())qb.pop(); // 若qb非空,qb出队
return 1;
}
vector<int>x,y; //定义两个向量x和y
while(!qa.empty()){ //当qa非空时候
x.push_back(a[qa.front()]);
qa.pop(); //将
}
while(!qb.empty()){
y.push_back(a[qb.front()]);
qb.pop();};
return solve(x)+solve(y);
}
//solve1求k边连通分量
int solve1(vector<int> a){ //a={0,1,2,3,4}
int n=a.size(); //n是节点的个数 n=5
if(n<=1)return 1; //如果节点个数小于等于1则返回1
int t;
for(int i=0;i<n;i++)
for(int j=0;j<n;j++){
grid[i][j]=side[a[i]][a[j]]; // 将side赋值给grid
}
if(stoerwagner(n)==K){
while(!qa.empty())qa.pop(); // 若qa非空,qa出队
while(!qb.empty())qb.pop(); // 若qb非空,qb出队
return 1;
}
vector<int>x,y; //定义两个向量x和y
while(!qa.empty()){ //当qa非空时候
x.push_back(a[qa.front()]);
qa.pop(); //将
}
while(!qb.empty()){
y.push_back(a[qb.front()]);
qb.pop();};
return solve1(x)+solve1(y);
}
int main(){
int n,m;
K=1;
n=14;
m=29;
//memset(side,0,sizeof(side));
VQuery.push_back(0);
VQuery.push_back(5);
AQuery.push_back('music');
AQuery.push_back('art');
attribute[0].push_back('film');
attribute[0].push_back('music');
attribute[1].push_back('film');
attribute[1].push_back('music');
attribute[2].push_back('film');
attribute[2].push_back('music');
attribute[3].push_back('film');
attribute[3].push_back('music');
attribute[4].push_back('film');
attribute[5].push_back('music');
attribute[5].push_back('art');
attribute[6].push_back('music');
attribute[7].push_back('music');
attribute[7].push_back('art');
attribute[8].push_back('music');
attribute[8].push_back('art');
attribute[9].push_back('art');
attribute[10].push_back('art');
attribute[10].push_back('sport');
attribute[11].push_back('art');
attribute[12].push_back('art');
attribute[13].push_back('music');
attribute[13].push_back('art');
attribute[13].push_back('sport');
side[0][1]=1;
side[1][0]=1;
side[0][2]=1;
side[2][0]=1;
side[0][3]=1;
side[3][0]=1;
side[0][4]=1;
side[4][0]=1;
side[1][2]=1;
side[2][1]=1;
side[1][3]=1;
side[3][1]=1;
side[1][4]=1;
side[4][1]=1;
side[2][3]=1;
side[3][2]=1;
side[2][4]=1;
side[4][2]=1;
side[3][4]=1;
side[4][3]=1;
side[3][4]=1;
side[3][6]=1;
side[6][3]=1;
side[4][6]=1;
side[6][4]=1;
side[4][8]=1;
side[8][4]=1;
side[4][11]=1;
side[11][4]=1;
side[6][5]=1;
side[5][6]=1;
side[6][7]=1;
side[7][6]=1;
side[6][8]=1;
side[8][6]=1;
side[5][8]=1;
side[8][5]=1;
side[5][7]=1;
side[7][5]=1;
side[7][8]=1;
side[8][7]=1;
side[8][9]=1;
side[9][8]=1;
side[8][10]=1;
side[10][8]=1;
side[10][13]=1;
side[13][10]=1;
side[9][10]=1;
side[10][9]=1;
side[9][11]=1;
side[11][9]=1;
side[11][12]=1;
side[12][11]=1;
side[10][12]=1;
side[12][10]=1;
side[9][12]=1;
side[12][9]=1;
side[10][11]=1;
side[11][10]=1;
vector<int>graph;
for(int i=0;i<n;i++){
graph.push_back(i);
}
//求连通性图
int ab=solve(graph);
while(ab<14){
K=K+1;
ab=solve(graph);
}
printf("连通度图为:\n");
for(int i=0;i<14;i++){
for(int j=0;j<14;j++)
{
printf("%d ",sc[i][j]);
}
printf("\n");
}
}
运行结果就是这样啦,可以看到连通性图求解是正确的。
因为我在学习的过程中特别希望有人已经写过这个算法了(hhh毕竟copy真的很香),所以我就把我写的分享一下,希望能够给在学习图搜索的童鞋一些帮助吧。
后续也可能会在这里继续分享一些相关的算法,也算是自己的一个学习笔记了。
如果有错误的地方,也欢迎指正呀。