图学习总结(二)

最小生成树

一、Prim算法

G=(V, E)是具有n个顶点的连通网,T=(U, TE)是G的最小生成树, T的初始状态为U={u0}(u0∈V),TE={ },重复执行下述操作:在所有uUvV-U的边中找一条代价最小的边(u, v)并入集合TE,同时v并入U,直至U=V

#include<bits/stdc++.h>
const int maxsize=100;
using namespace std;
int edge[maxsize][maxsize];
int vertexNum;
int edgeNum;
int Minedge(int a[],int n)
{
    int i;
    int minn=100;
    for(i=1;i<=n;i++)
    {
        if(a[i]<minn&&a[i]!=0)
        {
            minn=a[i];
        }
    }
    for(i=1;i<=n;i++)
    {
        if(a[i]==minn)
        {
            break;
        }
    }
    return i;
}
void Prim(int v)
{
    int i,j,k;
    int adjvex[maxsize],lowcost[maxsize];
    for(i=1;i<=vertexNum;i++)
    {
        lowcost[i]=edge[v][i];
        adjvex[i]=v;
    }
    lowcost[v]=0;
    for(k=2;k<=vertexNum;k++)
    {
        j=Minedge(lowcost,vertexNum);
        cout<<lowcost[j]<<" ";
        lowcost[j]=0;
        for(i=1;i<=vertexNum;i++)
        {
            if(edge[i][j]<lowcost[i])
            {
                lowcost[i]=edge[i][j];
                adjvex[i]=j;
            }
        }
    }
}
int main()
{
    cin>>vertexNum>>edgeNum;
    for(int i=1;i<=vertexNum;i++)
    {
        for(int j=1;j<=vertexNum;j++)
        {
            cin>>edge[i][j];
        }
    }
    Prim(1);
    cout<<endl;
}

二、kruskal算法

1.设无向连通网为G=(V, E),令G的最小生成树为T=(U, TE),其初态为UVTE={ },2.然后,按照边的权值由小到大的顺序,考察G的边集E中的各条边。(1)若被考察的边的两个顶点属于T的两个不同的连通分量,则将此边作为最小生成树的边加入到T中,同时把两个连通分量连接为一个连通分量;(2)若被考察边的两个顶点属于同一个连通分量,则舍去此边,以免造成回路,3.如此下去,当T中的连通分量个数为1时,此连通分量便为G的一棵最小生成树。

#include<bits/stdc++.h>
const int maxsize=100;
using namespace std;
int vertexNum;
int edgeNum;
struct Edge
{
    int from;
    int to;
    int weight;
}e[1000];
bool cmp(Edge a,Edge b)
{
    return a.weight<b.weight;
}
int FindRoot(int parent[],int v)
{
    int t=v;
    while(parent[t]>-1)
    {
        t=parent[t];
    }
    return t;
}
void Kruskal()
{
    int num=0,i,vex1,vex2;
    int parent[vertexNum];
    for(i=1;i<=vertexNum;i++)
    {
        parent[i]=-1;
    }
    for(num=1,i=1;num<vertexNum;i++)
    {
        vex1=FindRoot(parent,e[i].from);
        vex2=FindRoot(parent,e[i].to);
        if(vex1!=vex2)
        {
            cout<<e[i].from<<" "<<e[i].to<<" ";
            parent[vex2]=vex1;
            num++;
        }
    }
}
int main()
{
    cin>>vertexNum>>edgeNum;
    int cnt=0;
    for(int i=1;i<=vertexNum;i++)
    {
        for(int j=1;j<=vertexNum;j++)
        {
            int x;
            cin>>x;
            if(j>i&&x!=100)
            {
                cnt++;
                e[cnt].from=i;
                e[cnt].to=j;
                e[cnt].weight=x;
            }
        }
    }
    sort(e+1,e+cnt+1,cmp);
    Kruskal();
    cout<<endl;
}

最短路径

一、Dijkstra算法

1.设置一个集合S存放已经找到最短路径的顶点,S的初始状态只包含源点v,2.对viV-S,假设从源点vvi的有向边为最短路径(从v到其余顶点的最短路径的初值)。3.以后每求得一条最短路径v, …, vk,就将vk加入集合S中,并将路径v, …, vk , vi与原来的假设相比较,取路径长度较小者为最短路径。重复上述过程,直到集合V中全部顶点加入到集合S中。

#include<bits/stdc++.h>
const int inf=9999;
const int maxsize=100;
using namespace std;
int vertexNum;
int edgeNum;
int edge[maxsize][maxsize];
int s,e;
int dist[maxsize],path[maxsize];
bool v[maxsize];
bool Dijkstra()
{
    bool flag;
	for(int i=0;i<vertexNum;i++)
	{
       dist[i]=edge[s][i];
       v[i]=0;
	   if(dist[i]!=inf)
	      path[i]=s;
	   else
	      path[i]=-1;
	}
    dist[s]=0;
    v[s]=1;
    for(int i=0;i<vertexNum;i++)
	{
	   int minn=inf;
	   int k=-1;
	   for(int j=0;j<vertexNum;j++)
	   {
		   if(minn>dist[j]&&!v[j])
		   {
			  k=j;
			  minn=dist[j];
		   }
	   }
       if(k==-1||k==e)
	   {
		  if(k==-1)
		    flag=0;
		  else
		    flag=1;
		  break;
	   }
	   v[k]=1;
	   for(int j=0;j<vertexNum;j++)
	   {
		   if(dist[j]>dist[k]+edge[k][j])
		   {
			   dist[j]=dist[k]+edge[k][j];
			   path[j]=k;
		   }
	   }
	}
	return flag;
}
void Output()
{

	 stack<int>way;
	 int it;
	 it=path[e];
	 way.push(it);
	 while(s!=it)
	 {
		 it=path[it];
		 way.push(it);
	 }
	 cout<<dist[e]<<endl;
     while(!way.empty())
	 {
		 cout<<"v"<<way.top()<<" ";
		 way.pop();
	 }
     cout<<"v"<<e;
}
int main()
{
    cin>>vertexNum>>edgeNum;
    cin>>s>>e;
    for(int i=0;i<vertexNum;i++)
    {
        for(int j=0;j<vertexNum;j++)
        {
            edge[i][j]=inf;
        }
    }
    for(int i=0;i<edgeNum;i++)
    {
        int x,y,w;
        cin>>x>>y>>w;
        edge[x][y]=w;
    }
    if(!Dijkstra())
    {
        cout<<"no answer"<<endl;
    }
    else
    {
        Output();
	    cout<<endl;
    }
}

二、Floyd算法

设图g用邻接矩阵法表示, 求图g中任意一对顶点vi、 vj间的最短路径。(-1) 将vi到vj 的最短的路径长度初始化为(vi,vj), 然后进行如下n次比较和修正:(0) 在vi、vj间加入顶点v0,比较(vi, v0, vj)和(vi, vj)的路径的长度,取其中较短的路径作为vi到vj的且中间顶点号不大于0的最短路径。 (1)  在vi、vj间加入顶点v1,得(vi, …,v1)和(v1, …,vj),其中:(vi, …, v1)是vi到v1 的且中间顶点号不大于0的最短路径, (v1, …, vj) 是v1到vj 的且中间顶点号不大于0的最短路径, 这两条路径在上一步中已求出。 将(vi, …, v1, …, vj)与上一步已求出的且vi到vj 中间顶点号不大于0的最短路径比较,取其中较短的路径作为vi到vj 的且中间顶点号不大于1的最短路径。(2)在vi、vj间加入顶点v2,得(vi, …, v2)和(v2, …, vj), 其中:(vi, …, v2)是vi到v2 的且中间顶点号不大于1的最短路径,  (v2, …, vj) 是v2到vj 的且中间顶点号不大于1的最短路径,这两条路径在上一步中已求出。 将(vi, …, v2, …, vj)与上一步已求出的且vi到vj 中间顶点号不大于1的最短路径比较, 取其中较短的路径作为vi到vj 的且中间顶点号不大于2的最短路径。……

#include<bits/stdc++.h>
const int inf=9999;
const int maxsize=100;
using namespace std;
int vertexNum;
int edgeNum;
int edge[maxsize][maxsize];
int path[maxsize][maxsize];
void dfs(int x,int y)
{
     int k=path[x][y];
     if(k==-1)
        return;
	 dfs(x,k);
	 cout<<"v"<<k<<" ";
	 dfs(k,y);
}
void Floyd()
{
    for(int i=0;i<vertexNum;i++)
    {
        for(int j=0;j<vertexNum;j++)
        {
            for(int k=0;k<vertexNum;k++)
            {
                if(i==j||j==k||k==i)
                    continue;
                if(edge[i][j]>edge[i][k]+edge[k][j])
		        {
			       edge[i][j]=edge[i][k]+edge[k][j];
                   path[i][j]=k;
                }
            }
        }
    }
    bool flag=0;
    for(int i=0;i<vertexNum;i++)
    {
        for(int j=0;j<vertexNum;j++)
        {
            if(edge[i][j]!=inf)
            {
                flag=1;
                cout<<edge[i][j]<<" ";
			    cout<<"v"<<i<<" ";
                dfs(i,j);
                cout<<"v"<<j<<" "<<endl;
            }
        }
    }
    if(flag==0)
    {
        cout<<"no answer"<<endl;
    }
}
int main()
{
    cin>>vertexNum>>edgeNum;
    for(int i=0;i<vertexNum;i++)
    {
        for(int j=0;j<vertexNum;j++)
        {
            edge[i][j]=inf;
            path[i][j]=-1;
        }
    }
    for(int i=0;i<edgeNum;i++)
    {
        int x,y,w;
        cin>>x>>y>>w;
        edge[x][y]=w;
    }
    Floyd();
}

 

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值