#include <bits/stdc++.h>
using namespace std;
const int maxn=100,bignum=100001;
int g[maxn][maxn],dis[maxn],t[maxn],siz;
bool state[maxn];
void creat(int k)
{
memset(g,0,sizeof(g));
for(int i=0;i<=siz;i++)
{
for(int j=0;j<=siz;j++)
{
cin>>g[i][j];
}
}
for(int i=0;i<=siz;i++)
{
dis[i]=g[k][i];
}
memset(state,true,sizeof(state));
state[k]=false;
memset(t,0,sizeof(t));
t[k]=-1;
}
void addnode(int k)
{
siz++;
int cur;
for(int i=0;i<=siz;i++)
{
cin>>cur;
g[siz][i]=cur;
g[i][siz]=cur;
}
dis[siz]=g[k][siz];
}
int findminandstate()
{
int minpos,minsum=bignum;
for(int i=0;i<=siz;i++)
{
if(state[i]==true)
{
if(dis[i]<minsum)
{
minpos=i;
minsum=dis[i];
}
}
}
return minpos;
}
void dj(int k)
{
int lastpos=k;
for(int j=0;j<=siz;j++)
{
if(j==k)continue;
int minpos=findminandstate();
for(int i=0;i<=siz;i++)
{
if(state[i]&&((g[minpos][i]+dis[minpos])<dis[i]))
{
state[minpos]=false;
dis[i]=g[minpos][i]+dis[minpos];
t[i]=minpos;
}
}
}
}
int main()
{
int k;
cin>>siz>>k;
siz--;k--;
creat(k);
addnode(k);
dj(k);
for(int i=0;i<=siz;i++)cout<<t[i]+1<<" ";
cout<<endl;
for(int i=0;i<=siz;i++)cout<<dis[i]<<" ";
return 0;
}
void prtg()
{
for(int i=0;i<=siz;i++)
{
for(int j=0;j<=siz;j++)
{
cout<<g[i][j]<<" ";
}
cout<<endl;
}
}
/*
6 1
0 50 100000 40 25 10
50 0 15 20 100000 25
100000 15 0 10 20 100000
40 20 10 0 10 25
25 100000 20 10 0 55
10 25 100000 25 55 0
5 1
0 50 100000 40 25
50 0 15 20 100000
100000 15 0 10 20
40 20 10 0 10
25 100000 20 10 0
10 25 100000 25 55 0
*/
maxn:可放的最大节点数,因为以邻接矩阵存储所以开一个较小的数
Bignum:代码中用的大数,防止int溢出设一个不大不小的100001
g:邻接矩阵,存放输入数据
dis:存储节点到根节点距离的数组
t:存储最小生成树
siz:存储输入的邻接矩阵大小
state;存储某个节点是否已挂上生成树,真表示未挂上
creat():一次性读入某个邻接矩阵
addnode():增加节点,需要在调用dj之前使用,不知道能有什么卵用
findminandstate():中间函数,用来找没挂上生成树的离源最近节点
dj():dj]
大概回忆一下dj的思路
目的:求一个边带权有向图中单源的最小生成树
思路的第一步:对于图中一个节点vi,它所邻接到的所有点中,把邻接边权值最小的那个点记作vk,则e=vi-vk一定是最小生成树上的一条边
呃这么写以后肯定看不懂,那就通俗的来说,想从甲地到乙地,我们有一条路能直接从甲到乙,我们还有很多条别的路能直接到不知道什么鬼的地方。而这条直接从甲到乙的路比别的路的<甲地到第一个下车口的距离>还要短,那么显然,不走从甲到乙的这条直接的路的都在绕弯子。
这个第一步的用处在于:每一次从图上选择一个据起点最近的点,从起点到它的那条路肯定是在所需的树上的。
那么为了能一步步走下去,我们需要一个数组,保存目前从起点到每一个节点的距离。目前没有发现有路的,就记作无限远。
还有一个就是,每一次确定了一个点后,需要记录下这个确定的状态,以后找点的时候就可以忽略这个点了,同样用一个数组来存。
这样一来就可以如此描述:
起始步:将所有起点邻接到的节点,将这个边的长度作为目前起点到这个点的距离记录到数组里。
循环步:对目前距起点最近且未挂上树的节点,挂上树,并且对这个节点邻接到的所有点便利一次,若<这个点到某个点的边权值>+<起点到这个点的距离>小于<此处的<某个点>到起点的距离>,那么就把<此处的<某个点>到起点的距离>更新为<这个点到某个点的边权值>+<起点到这个点的距离>
循环终止条件:所有节点都挂上树了