#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;
}