问题描述
支撑树的插点数目问题
支撑树插点数目问题算法描述:
注意:这里的输入还应加上d和B
算法的java实现:
package sy2;
import sy1.*;
public class TheInsertNodeOfSpanningTree {
public final static int Inf=Integer.MAX_VALUE;//表示整型无穷大,用来标识两个顶点是否有边相连
public int[][] M;//有向图邻接矩阵
public Vnode[] V;//有向图的顶点集
public Vnode X[];//反圈中的顶点集
public Arc F[];//反圈中的边集合
public int ArcNum;
public int num=0;//反圈中的边数
public int InsertTree[][];
public Vnode Insert[];
public TheInsertNodeOfSpanningTree(int M[][],Vnode V[],int ArcNum) {
// TODO Auto-generated constructor stub
this.M=M;
this.V=V;
this.ArcNum=ArcNum;
X=new Vnode[V.length];
X[0]=new Vnode(V[0].getV(),V[0].getVw());
V[0].setFlag(true);
for(int i=1;i<X.length;i++){
X[i]=new Vnode("",i);
}
F=new Arc[ArcNum];
for(int i=0;i<ArcNum;i++){
F[i]=new Arc(null,null,Inf);
}
}
public boolean TheMinimalSpanningTree(){
boolean flag1=true;
boolean flag=false;//用来判断反圈中的顶点集是否等于图的顶点集
int min=Inf;//用来求取最小权值弧长
int index1=0;//用来表示权值最小的非反圈对应点的位置
int index2=0;//用来表示权值最小的反圈对应点的位置
while(flag==false){//表示反圈中的顶点集不等于图的顶点集
min=Inf;
for(int i=0;i<X.length;i++){
if(!X[i].getV().equals("")){
for(int j=0;j<V.length;j++){
if(V[j].isFlag()==false && M[X[i].getVw()][V[j].getVw()]!=Inf){
if(M[X[i].getVw()][V[j].getVw()]<min){
min=M[X[i].getVw()][V[j].getVw()];//寻找权值最小的边
index1=j;
index2=i;
//System.out.println(index2+" "+index1);
}// if
}// if
}// for
}// if
}// for
if(index1!=-1){//表示反圈不为空
X[index1]=new Vnode(V[index1].getV(),index1);//将该点加入反圈的点集合
V[index1].setFlag(true);
F[num]= new Arc(X[index2],V[index1],M[index2][index1]);//将该边加入反圈集合
num++;
}
else{//表示若反圈为空
if(num==V.length-1){
flag=true;
}else{
//System.out.println("此图不连通,不存在最小支撑树!");
for(int i=0;i<ArcNum;i++){
F[i]=new Arc(null,null,Inf);
}
for(int i=1;i<X.length;i++){
X[i]=new Vnode("",i);
}
flag1=false;
break;
}
}
index1=-1;
index2=-1;
}//while
return flag1;
}
public boolean InsertTree(int B,int d){
boolean flag=true;//判断能否找到支撑树的插点树
int sum=0;
int Num=0;//表示总的加点数
if(!TheMinimalSpanningTree()){
flag=false;//表示不存在最小支撑树
}
int InsertNum[]=new int[num];//记录支撑树每条边上的插点数
for(int i=0;i<num;i++){
if(F[i].getWeight()!=Inf){
sum=sum+F[i].getWeight();
}
}
if(sum>B){
flag=false;//表示不存在最小支撑树
}
else{
//System.out.println(num);
for(int i=0;i<num;i++){
double t;
if(F[i].getWeight()!=Inf){
t=(double)F[i].getWeight()/d;
if(t==(int)t){
InsertNum[i]=(int)t-1;
}else{
InsertNum[i]=(int)t;
}//else
}//if
Num=Num+InsertNum[i];
}//for
System.out.println("总插点树:"+Num);
InsertTree=new int[V.length+Num][V.length+Num];
Insert=new Vnode[V.length+Num];
for(int i=0;i<V.length+Num;i++){
for(int j=0;j<V.length+Num;j++){
if(i<V.length && j<V.length){
InsertTree[i][j]=M[i][j];
}
else{
InsertTree[i][j]=Inf;
}
}
if(i<V.length){
Insert[i]=V[i];
}else{
Insert[i]=new Vnode("",i);
}
}
int index=V.length;
String s;
for(int i=0;i<num;i++){
if(InsertNum[i]!=0){//表示对应这条边插点
InsertTree[F[i].getFirstNode().getVw()][F[i].getLastNode().getVw()]=Inf;
InsertTree[F[i].getLastNode().getVw()][F[i].getFirstNode().getVw()]=Inf;
InsertTree[F[i].getFirstNode().getVw()][index]=d;
InsertTree[index][F[i].getFirstNode().getVw()]=d;
s="v"+Integer.toString(index+1);
Insert[index]=new Vnode(s,index);
for(int j=0;j<InsertNum[i]-1;j++){
InsertTree[index][index+1]=InsertTree[index+1][index];
index++;
s="v"+Integer.toString(index+1);
Insert[index]=new Vnode(s,index);
}
InsertTree[index][F[i].getLastNode().getVw()]=InsertTree[F[i].getLastNode().getVw()][index]=F[i].getWeight()-InsertNum[i]*d;
}//if
}//for
}//if
return flag;
}
public static void main(String args[]) throws Exception{
MyGraph G=new MyGraph();
G.createGraph();
System.out.println("请输出所构建图的邻接矩阵:");
for(int i=-1;i<G.getVexNum();i++){
if(i<0){
System.out.print(" ");
for(int j=0;j<G.getVexNum();j++){
System.out.print(G.getVex(j)+" ");
}
System.out.println();
}else{
for(int j=-1;j<G.getVexNum();j++){
if(j<0){
System.out.print(G.getVex(i)+" ");
}
else{
if(G.arcs[i][j]==Inf){
System.out.print("INF"+" ");
}
else{
System.out.print(G.arcs[i][j]+" ");
}
}//else
}// if
System.out.println();
}// for
}//else
TheInsertNodeOfSpanningTree Insert=new TheInsertNodeOfSpanningTree(G.arcs,G.V,G.getArcNum());
if(!Insert.InsertTree(10, 1)){
System.out.println("不存在最小支撑树!");
}
else{
System.out.println("最小支撑树是:");
for(int i=0;i<Insert.num;i++){
if(Insert.F[i].getWeight()!=Inf){
System.out.println(Insert.F[i].getFirstNode().getV()+"------"+Insert.F[i].getLastNode().getV()+":weight="+Insert.F[i].getWeight());
}
}
System.out.println("其加细树是:");
for(int i=-1;i<Insert.InsertTree.length;i++){
if(i<0){
System.out.print(" ");
for(int j=0;j<Insert.InsertTree.length;j++){
System.out.print(Insert.Insert[j].getV()+" ");
}
System.out.println();
}else{
for(int j=-1;j<Insert.InsertTree.length;j++){
if(j<0){
System.out.print(Insert.Insert[i].getV()+" ");
}
else{
if(Insert.InsertTree[i][j]==Inf){
System.out.print("INF"+" ");
}
else{
System.out.print(Insert.InsertTree[i][j]+" ");
}
}//else
}// if
System.out.println();
}// else
}//for
}//else
}
}
程序分析:
本程序共包含1个class,3个method:
class:TheInsertNodeOfSpanningTree
method:
public boolean TheMinimalSpanningTree(): 利用反圈法求最小支撑树
public boolean InsertTree(int B,int d): 对相应的支撑树进行插点
main: 程序的主方法,调用上面的两个方法,找到对应图的最小支撑树,进行插点,并输出插点后的加细树
本实验总的来说难点在构造支撑树的加细树,下面我用一点例子来描述我的构造过程:
从上面的描述就可以找到构造邻接矩阵的规律,具体体现为如下的代码:
for(int i=0;i<num;i++){
if(InsertNum[i]!=0){//表示对应这条边插点
InsertTree[F[i].getFirstNode().getVw()][F[i].getLastNode().getVw()]=Inf; InsertTree[F[i].getLastNode().getVw()][F[i].getFirstNode().getVw()]=Inf;
InsertTree[F[i].getFirstNode().getVw()][index]=d;
InsertTree[index][F[i].getFirstNode().getVw()]=d;
s="v"+Integer.toString(index+1);
Insert[index]=new Vnode(s,index);
for(int j=0;j<InsertNum[i]-1;j++){
InsertTree[index][index+1]=InsertTree[index+1][index];
index++;
s="v"+Integer.toString(index+1);
Insert[index]=new Vnode(s,index);
}
InsertTree[index][F[i].getLastNode().getVw()]=F[i].getWeight()-InsertNum[i]*d;
InsertTree[F[i].getLastNode().getVw()][index]=F[i].getWeight()-InsertNum[i]*d;
}//if
}//for
实例演示:
对下面给出的两个图进行插点:
对于第一幅图:
对于第二幅图:
这里的第二幅图是不连通的,因此不存在其最小支撑树,插点也就没有意义了