title: 通信网络设计问题(kruskal求最短路)
date: 2019-08-24 23:34:43
tags: 数学建模
某通信公司拟建一个具有80个结点的通信网络,需要在这些结点之间铺设线路,进行数据传输。结点之间的距离和铺设线路的单位费用见附件1,请对以下问题进行研究:
问题1.要使得通信网络的总铺设费用最省,请建立问题的数学模型,设计求解算法,给出铺设方案,并讨论方案的可靠性;
解决:我们采用kruskal算法找出最短路,再依次断开每个点,计算最大连通分支里的节点数,从而计算出可靠性,再进行分析
注意:graphconncomp
命令的使用,它可以用来求连通分支,功能有点像并查集啥的,但是更方便…对于矩阵存储也更合适,再用C++敲我就是猪…
% kruskal算法
function [result]=kruskal(a)
% 输入:a—邻接矩阵,a(i,j)是指i到j之间的权值
% 输出:result—第一、二、三行分别代表最小生成树边的起点、终点、权集合
[i,j,b]=find(a);
data=[i';j';b'];index=data(1:2,:);
loop=length(a)-1;
result=[];
while length(result)<loop
temp=min(data(3,:));
flag=find(data(3,:)==temp);
flag=flag(1);
v1=index(1,flag);v2=index(2,flag);
if v1~=v2
result=[result,data(:,flag)];
end
index(find(index==v2))=v1;
data(:,flag)=[];
index(:,flag)=[];
end
end
%以下部分在命令窗口中输入,以绘制生成的最短路图
%kruskal(a) %a中导入边权
%A=ans(1,:);
%B=ans(2,:);
%C=ans(3,:);
%SS=sparse(A,B,C,80,80);
%view(biograph(ST,[],'ShowArrows','off','ShowWeights','on'))
#include <iostream>
#include <map>
#include <algorithm>
#include <cstring>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <stdlib.h>
#define ll long long
const int maxn=105;
const int inf=0x3f3f3f3f;
const double eps=1e-6;
using namespace std;
int nodenum[maxn];
int parent[maxn];
int find_root(int x)
{
if(x!=parent[x])
parent[x]=find_root(parent[x]);
return parent[x];
}
void Union(int x,int y)
{
int rx=find_root(x);
int ry=find_root(y);
if(rx==ry)
return;
else
{
parent[ry]=rx;
nodenum[rx]+=nodenum[ry];
}
}
int main()
{
freopen("in1.txt","r",stdin);
//freopen("out.txt","w",stdout);
int t=80;
for(int k=1;k<=80;k++)
{
int n=79;
for(int i=0;i<maxn;i++)
{
parent[i]=i;
nodenum[i]=1;
}
int maxnode=80;
int v,w;
//for(int i=1;i<=n;i++)
while(scanf("%d%d",&v,&w)&&v&&w)
{
Union(v,w);
}
int cnt=0;
int ans[maxn];
for(int i=0;i<maxn;i++)
ans[i]=0;
int f[maxn];
int maxi=-1;
for(int i=1;i<=maxnode;i++)
{
if(parent[i]==i)
{
ans[cnt]=nodenum[i];
if(nodenum[i]>maxi)
maxi=nodenum[i];
//f[cnt]=i;
cnt++;
}
}
//for(int i=0;i<cnt;i++)
//cout<<f[i]<<endl;
//cout<<"去掉第"<<k<<"个结点:\t"<<
cout<<"块数:"<<cnt<<" \t每个块节点个数:";
for(int i=0;i<cnt;i++)
cout<<ans[i]<<" ";
cout<<endl;
double t=maxi/80.0;
cout<<"可靠性:"<<t<<endl;
}
return 0;
}
问题2.考虑到通信网络结点的可靠性,若要求任意一个结点出现故障时,其它结点间仍然能够保持通信畅通的可能性都达到90%,请建立问题的数学模型,设计求解算法,并给出使总铺设费用最少的铺设方案;
解决:相当于从第一问取出可靠性最低的点,然后找出避开这个点,再把几个块连接起来,使其达到90%可靠性要求,再次遍历80个点,找不满足可靠性要求的点,再给他们加边
注意:其实没有办法找到最优解,只能无限接近它,设定为全部结点到达90%可靠性退出循环时,产生了死循环,所以我们设定允许2~3个结点可以不达到90%时,可以得到较优的结果
function main()
A=[];
B=[];
%A,B构成系数矩阵
D=[];%放边权的邻接矩阵
global G;
G=sparse(A,B,true,80,80);% 构造稀疏矩阵
global t;
global num;
global temp;
global S;
%k=3;
sum=0;
func3();
while(1)
minx=1;
cn=0;
for i=1:80
if(t(i)<minx)
minx=t(i);
mint=i;%记录了当前最小的那个结点
end
if(t(i)<0.9)
cn=cn+1;
end
end
%mint
if(cn<3)%都大于90%了
break;
end
%找到最小结点mint了,要求出连接的两块的最短路minl
func1(mint);
m=0;
n=0;
mi=0;
%num
for i=1:S
if(num(i)>mi)
mi=num(i);
m=i;
end
end
mii=0;
for i=1:S
if(num(i)~=mi&&num(i)>mii)
mii=num(i);
n=i;
end
end
%temp
% m
% n
a=temp{m};
b=temp{n};
c=D(a,b);
mind=min(min(c));
sum=sum+mind;
mind
[x,y]=find(D==mind);
%连接起来,再次计算每个点的可靠性
x1=x(1);
y1=y(1);
G(x1,y1)=1;
G(y1,x1)=1;
func3();
%t
x1
y1
% k=k-1;
end
sum
%可求出1~80号结点的可靠性
function p=func3()
global t;
for i=1:80
t(i)=func1(i);
end
%求出每一组的可靠性
function ans=func1(k)
global G;
g=G;
g(k,:)=0;
g(:,k)=0;
global S;
[S,C] = graphconncomp(g);
global temp;
global num;
temp=cell(S,1);
for i=1:S
z=find(C==i);
temp{i}=z;
num(i)=length(z);
end
temp;
%求可靠性
maxn=0;
for i=1:S
if(num(i)>maxn)
maxn=num(i);
end
end
ans=maxn/80;
问题3:考虑到通信网络链路的可靠性,若要求任意一条链路被破坏时,能够保持通信畅通的结点都能够达到90%,请建立问题的数学模型,设计求解算法,并给出使总铺设费用最少的铺设方案。
解决:第三问和第二问差不多求解,甚至更为简单,因为每次断开一条边,只会把所有的点分成两个部分