最小生成树
一、Prim算法
设G=(V, E)是具有n个顶点的连通网,T=(U, TE)是G的最小生成树, T的初始状态为U={u0}(u0∈V),TE={ },重复执行下述操作:在所有u∈U,v∈V-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),其初态为U=V,TE={ },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.对vi∈V-S,假设从源点v到vi的有向边为最短路径(从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();
}