#include<iostream>
#include<stack>
#include<queue>
#include<iomanip>
#include<deque>
#include<fstream>
using namespace std;
class Mgraph
{
public:
 Mgraph(){}
 
 ~Mgraph(){}
 void CreatMGraph();
 void DFS(int);
 void DFS1(int);
 void BFS(int);
 void print();
 void prim();
 int mini();
 int low();
 int LocateVex(char);
 void kruskal();
 void Dijkstra();
 void Floyd();
private:
 int number;//顶点数
 int arcnum;//边数
 char vexs[50];// 放顶点的
 int arcs[50][50];//放权值的
 int visited[50]; // 标记用的
// primnode closeddege[50];//prim
// adknode dist[50];//最短路径
 //int D[20][20];
// int P[20][20][20];//算法路径
};

int Mgraph::LocateVex(char s)
{
 for(int i=0;i<number;i++)
 {
  if(vexs[i]==s)
   return i;
 }return -1;
}

void Mgraph::print()
{
 cout<<"顶点数: ";
 for(int k=0;k<number;k++)
  cout<<vexs[k];
 cout<<endl;
 for(int i=0;i<number;i++)
 {
  for(int j=0;j<number;j++)
   cout<<setw(6)<<arcs[i][j]<<" ";
  cout<<endl;
 }
 for(int m=0;m<number;m++)
  cout<<visited[m];
 cout<<endl;
}

void Mgraph::CreatMGraph ()
{
 char vex1,vex2;//结点的名字
 int i,j,k,m;
  ifstream cin("a.txt");
 cout<<"请输入定点数,边数"<<endl;
 cin>>number>>arcnum;
 cout<<"请输入顶点(字符串类型): "<<endl;
 for(i=0;i<number;i++)
  cin>>vexs[i];
 for(i=0;i<number;i++)
 {
  for(j=0;j<number;j++)
  {
   arcs[i][j]=100;
  }
 }

 for(k=0;k<arcnum;k++)
 {
  cout<<"请输入边的两个顶点及边的权值: "<<endl;
  cin>>vex1>>vex2>>m;
  i=LocateVex(vex1);
  j=LocateVex(vex2);
  arcs[i][j]=m;
  arcs[j][i]=m;
 }
   memset(visited,0,sizeof(visited));
}

void Mgraph::DFS(int i)
{
 int j;
 cout<<vexs[i]<<"-------->";
 visited[i]=1;
 for(j=i+1;j<=number-1;j++) //顶点是按顺序存储的 j可以从i+1 开始
 {
  if((arcs[i][j]!=100)&&!visited[j])
   DFS(j);
 }
}

void Mgraph::DFS1(int j)
{
 stack<int>st;
 st.push(j);
 while(!st.empty ())
 {
  int i=st.top();
  st.pop();
  if(!visited[i])
      cout<<vexs[i]<<"------>";
  visited[i]=1;
  for(int k=number-1;k>=i+1;k--)
  {
   if(arcs[i][k]!=100 &&( !visited[k]))
    st.push(k);
  }
 }
}

void Mgraph:: BFS(int i)
{
  queue<int>qu; int k;
  qu.push(i);

  while(!qu.empty ())
  {
               int j=qu.front();
 qu.pop ();
 if(!visited[j])
   {cout<<vexs[j]<<"------>"; visited[j]=1;}

 for(k=j+1;k<=number-1;k++)
 {
                  if((arcs[j][k]!=100)&&!visited[k])
      {
                         cout<<vexs[k]<<"------>";visited[k]=1;
          qu.push(k);
       }
 }
    }
}


void Mgraph::kruskal()
{
 int a,b,k=0;
 int min=1000;
 int arcs1[20][20];
 for (int m=0;m<number;m++)
        visited[m]=m;      //每一个顶点属于一颗树

    for (int i=0;i<number;i++)
       for(int j=0;j<number;j++)
            arcs1[i][j]=arcs[i][j];

 while (k<=number-1)
 {
    min=1000;
   for (int i=0;i<number;i++)
   {
     for (int j=0;j<number;j++)
       {
         if (arcs1[i][j]<min)
           {
             a=i; b=j;  min=arcs1[i][j];
           }
       }
    }
  if (visited[a]!=visited[b])
  {
    cout<<"包括边("<<vexs[a]<<","<<vexs[b]<<")";
    k++;
    for (int n=0;n<number;n++)//弧尾端点所在 树编号 小于 弧头端点所在树编号 
     {
        if (visited[n]==visited[b])  //将连同分量的编号设为这些点里编号最小的那个
           { if(visited[a]<visited[n])
                  visited[n]=visited[a];
             else
                  visited[a]=visited[n];
             break;
            }
      }
    //更新结点 所在树的标号 ps:某个连同分量(也就是这里的树)都有很多结点,某连同分量的编号 用此连同分量中节点编号最小的那个
    for(int h=0;h<number;h++)
    {
      for(int l=0;l<number;l++)
       {
       if(visited[h]==l)
      visited[h]=visited[l];
       }
     }
  }
  else
   arcs1[a][b]=arcs[b][a]=1000;
 }
 
}

 

void Mgraph::prim()
{
  int q=0; int i=0; int s[20]; //用来放 加入树的点集合。存的是 点的编号。
  char ch[20];   s[0]=0;   int a,b;
 
  int h=1;//s数组中的编号,个数


 while(i<number)
 {   int min=100;
  for(int p=0;p<h;p++)
  {   
   for(int k=0;k<number;k++)
   {
    if(arcs[(s[p])][k]<min)
    {
     if(visited[k]*visited[s[p]]!=1 && visited1[s[p]][k]!=1) // 如果两个s集合中的点被选为路径,会产生回路
     {
      
                      a=s[p]; b=k;
       min=arcs[a][b];
     } 
    }
   }
  }
  ch[q++]=vexs[a];    ch[q++]=vexs[b];   s[h++]=b;
  
  visited1[a][b]=1; visited1[b][a]=1;// 标记某路径已经加入到 路径集合中

        visited[a]=1;  visited[b]=1;// 标记 是否在路径集合上
  i++;
 }

 for(i=0;i<number*2-2;i++)
 {
  if((i+1)%2==0)
  {   cout<<ch[i]<<"  "; }
  else
   cout<<ch[i];
 }
}

void Mgraph::Dijkstra ()
{
 cout<<"输入起始点";
 char u;
 cin>>u;
   int i=LocateVex(u);
   visited[i]=1;

   for(int j=0;j<number;j++)
   {
    dist[j].dist=arcs[i][j];
    dist[j].nodenum=0;
   }
   for(j=1;j<number;j++)
   {
    int distance=1000;
    int min=0;
    for(int n=0;n<number;n++)
    {
     if(!visited[n])
     {
      if(distance>dist[n].dist)
      {
       distance=dist[n].dist ;
       min=n;
      }
     }
    }
    int m=min;
    visited[m]=1;
    for(n=0;n<number;n++)
    {
     if(!visited[n])
     {
              if(dist[n].dist>dist[m].dist +arcs[m][n])
     {
      dist[n].dist=dist[m].dist +arcs[m][n];
      dist[n].nodenum=0;
                 
      //记录 路径功能 。
      for(int x=0;x<dist[m].nodenum ;x++)
      {
                     dist[n].way [x]=dist[m].way [x];// 将起点 到 m点 (也就是 刚才求的 最小路径的点) 的路径复制给。。。
      dist[n].nodenum ++;
      }
      dist[n].way[dist[n].nodenum ++]=vexs[m];
     }
     }
    }
   }

   //输出功能
  for (int n=0;n<number;n++)
  {
   if (n!=i)
   {
     if(dist[n].dist<1000)
     {
       cout<<vexs[i]<<"到"<<vexs[n]<<"的最近距离为:"<<dist[n].dist<<endl;
       cout<<"经过的顶点为:"<<vexs[i]<<"---->";
       for (int p=0;p<dist[n].nodenum;p++)
    {
          cout<<dist[n].way[p]<<"----->";
    }
       cout<<vexs[n]<<endl;
  }
     else
     cout<<vexs[i]<<"到"<<vexs[n]<<"没有通路"<<endl;
   }
  }
}

int main()
{
 Mgraph graph;
    graph.CreatMGraph ();
 graph.print();cout<<endl;
 //graph.DFS(0);cout<<endl;
 graph.BFS(0);
  //  graph.DFS1(0);
 return 0; 
}


kruskal
从权值数组中选择 最小的边长 number-1次 (number为点的数目) 且不可构成回路 ,就能得所求。

所以 问题的关键是 控制不构成回路   ------如何判断不构成回路呢?

初始化时,将每一个点都配有编号 ,代表 它所在的树 编号。 
找到一个权值最小的 线段AB时, 查找与visited[B]相等的 visited[n]  .





Dijkstra提出了一种根据动态的规划选择,最终得到最短路径的办法。从源点到个端点的最短路径长度分别为l1,l2,…lk .其中lx 为其中最短的一条。可以推断这条路径一定只有一条弧,不然就有一个比他更短的ly .第二条长度次短的最短路径可能产生在两种情况,其一是该点到源点有弧,其二是从已求的端点集合中到该点有弧。所以若该点到源点间有弧,就要求上面两种情况的最小值。假设DS[n][n]为有向图的邻接矩阵,P为已找到的最短路径的终点的集合。可以肯定初始状态只含有一个点.

算法的步骤为:

(1)源点。用一个一维数组DD[x]表示当前计算出的从源点到各个终点的最短路径值。DD[]的初始值为 DD[j]=DS[i,j]

(2)选择端点集中,到终点,路径最短的点,将其选入集合P中

    P[u]=min{DD[w] | wP, w图中的顶点集 }

(3)更新DD数组中尚未找到最短路径的顶点的对应值。

If(DD[u]+DS[u,w]<DS[w])

DD[w]=DD[u]+DD[u,w]

重复上述(2,3)的步骤既可得到从源点到所有终点的最短路径。

代码的实现:

voidMgraph::Dijkstra ()

{

       cout<<"输入起始点";

       char u;

       cin>>u;

   int i=LocateVex(u);

   visited[i]=1;

 

   for(int j=0;j<number;j++)

   {

         dist[j].dist=arcs[i][j];

         dist[j].nodenum=0;

   }

   for(j=1;j<number;j++)

   {

         int distance=1000;

         int min=0;

         for(int n=0;n<number;n++)

         {

                if(!visited[n])

                {

                        if(distance>dist[n].dist)

                        {

                               distance=dist[n].dist ;

                               min=n;

                        }

                }

         }

         int m=min;

         visited[m]=1;

         for(n=0;n<number;n++)

         {

                if(!visited[n])

                {

                                      if(dist[n].dist>dist[m].dist+arcs[m][n])

                       {

                              dist[n].dist=dist[m].dist +arcs[m][n];

                              dist[n].nodenum=0;

                 

                              //记录 路径功能 。

                              for(int x=0;x<dist[m].nodenum ;x++)

                              {

                                                           dist[n].way [x]=dist[m].way [x];//将起点到 m点 (也就是 刚才求的 最小路径的点) 的路径复制给。。。

                                    dist[n].nodenum ++;

                              }

                              dist[n].way[dist[n].nodenum ++]=vexs[m];

                       }

                }

         }

   }

 

   //输出功能

  for (int n=0;n<number;n++)

  {

   if (n!=i)

   {

     if(dist[n].dist<1000)

     {

        cout<<vexs[i]<<"到"<<vexs[n]<<"的最近距离为:"<<dist[n].dist<<endl;

        cout<<"经过的顶点为:"<<vexs[i]<<"---->";

        for (int p=0;p<dist[n].nodenum;p++)

         {

                    cout<<dist[n].way[p]<<"----->";

         }

         cout<<vexs[n]<<endl;

        }

     else

           cout<<vexs[i]<<"到"<<vexs[n]<<"没有通路"<<endl;

   }

  }

}

 

int main()

{

       Mgraph graph;

             graph.CreatMGraph ();

     graph.print();cout<<endl;

       graph.BFS(0);

       return 0; 

}

 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值