//
PRIM(简单版) 最小生成树算法 (Minimum Spanning Tree)
// 输入:图g; // 有向图或者无向图
// 输出:(1)最小生成树长sum;
// (2)最小生成树prev。
// 结构: 图g用邻接矩阵表示,最短边长dist用数组表示。
// 算法:Prim算法
// 复杂度:O(|V|^2)
#include < iostream >
#include < vector >
#include < list >
#include < iterator >
#include < algorithm >
#include < numeric >
#include < functional >
#include < climits >
using namespace std;
int n; // n : 顶点个数
vector < vector < int > > g; // g : 图(graph)(用邻接矩阵(adjacent matrix)表示)
vector < bool > known; // known : 各点是否已经选取
vector < int > dist; // dist : 已选取点集到未选取点的最小边长
vector < int > prev; // prev : 最小生成树中各点的前一顶点
int s; // s : 起点(start)
int sum; // sum : 最小生成树长
bool Prim() // 贪心算法(Greedy Algorithm)
{
known.assign(n, false);
dist.assign(n, INT_MAX);
prev.resize(n); // 初始化known、dist、prev。
dist[s] = 0; // 初始化起点到自身的路径长为0。
int i;
for (i = 0; i < n; ++i)
{
int min = INT_MAX, v;
for (int i = 0; i < n; ++i)
if (!known[i] && min > dist[i])
min = dist[i], v = i; // 寻找未知的最短路径长的顶点v,
if (min == INT_MAX) break; // 如果找不到,退出;
known[v] = true; // 如果找到,将顶点v设为已知,
sum += dist[v]; // 调整最小生成树长
for (int w = 0; w < n; ++w) // 遍历所有v指向的顶点w,
if (!known[w] && g[v][w] < INT_MAX && dist[w] > g[v][w])
dist[w] = g[v][w], prev[w] = v; // 调整顶点w的最短路径长dist和最短路径的前一顶点 prev。
}
return i == n; // 如果选取顶点个数为n,成功。
}
int main()
{
n = 7;
g.assign(n, vector<int>(n, INT_MAX));
g[0][1] = g[1][0] = 2; g[0][2] = g[2][0] = 4; g[0][3] = g[3][0] = 1;
g[1][3] = g[3][1] = 3; g[1][4] = g[4][1] = 10;
g[2][3] = g[3][2] = 2; g[2][5] = g[5][2] = 5;
g[3][4] = g[4][3] = 7; g[3][5] = g[5][3] = 8; g[3][6] = g[6][3] = 4;
g[4][6] = g[6][4] = 6;
g[5][6] = g[6][5] = 1;
s = 0; // 起点任选
sum = 0;
if (Prim())
{
cout << sum << endl;
for (int i = 1; i < n; ++i)
if(i != s) cout << prev[i] << "->" << i << endl;
}
else
{
cout << "Some vertex cann't be reached." << endl;
}
system("pause");
return 0;
}
/**/ /*=============================*/
/**/ /*
Write By LiveStar (2008.07.23)
*/
#include < stdio.h >
// max表示点,边的最大个数
#define max 1000
// wq表示两点的距离为无穷
#define wq 9999
// 邻接矩阵存储相应的边的权重
int mix[max][max];
// 输入并构造邻接矩阵
void input( int n, int m)
{
int i,j,sp,ep,wg;
//初始化邻接矩阵每个都是无穷大
for (i=0;i<n;i++)
for (j=0;j<n;j++)
mix[i][j]=wq;
printf("请输入边的起点、终点、权重(EX:1 2 3):\n");
for (i=0;i<m;i++)
{
scanf("%d %d %d",&sp,&ep,&wg);
//无向连通图
mix[sp][ep]=wg;
mix[ep][sp]=wg;
}
}
// 显示邻接矩阵
void output( int n, int m)
{
int i,j;
printf("\n邻接矩阵如下:\n\n");
for (i=0;i<n;i++)
{
for (j=0;j<n;j++)
printf("%d\t",mix[i][j]);
printf("\n");
}
}
// prim算法实现
void prim( int n, int r)
{
//a[max]用来存放各个点到已经标记点的集合的最短距离
int a[max];
//b[max]用来记录每个点的标记状态,false表示还没标记。
bool b[max];
int i,j,k,min;
//初始化从根节点开始
for (i=0;i<n;i++)
{
a[i]=mix[r][i];
b[i]=false;
}
b[r]=true;
printf("\n依次被标记的点及相应边的权重:\n");
printf("%d\t%d\n",r,0);
for (i=0;i<n-1;i++)//还剩n-1个点
{
k=0;
min=wq;
for (j=0;j<n;j++)
{
//第j个点到已经标记点的集合的距离最小且这个点还没有被标记
//k记录下一个将被标记的点
if (a[j]<min&&b[j]==false)
{
min=a[j];
k=j;
}
}
b[k]=true;//标记节点k
printf("%d\t%d\n",k,min);
//更新a[]里的状态,时刻保持最新的状态
//存放各个点到已经标记点的集合的最短距离
for (j=0;j<n;j++)
{
if (mix[k][j]<a[j])
{
a[j]=mix[k][j];
}
}
}
}
int main()
{
//n是点的个数 ,m是边的个数
int n,m,r;
printf("请输入点的个数和边的个数(EX:1 3):\n");
scanf("%d %d",&n,&m);
//输入并构造邻接矩阵
input(n,m);
//显示邻接矩阵
output(n,m);
while (1)
{
printf("\n请输入根节点(-1跳出):\n");
scanf("%d",&r);
if(r==-1)
break;
//prim算法实现
prim(n,r);
printf("\n\n");
}
return 0;
}
// 输入:图g; // 有向图或者无向图
// 输出:(1)最小生成树长sum;
// (2)最小生成树prev。
// 结构: 图g用邻接矩阵表示,最短边长dist用数组表示。
// 算法:Prim算法
// 复杂度:O(|V|^2)
#include < iostream >
#include < vector >
#include < list >
#include < iterator >
#include < algorithm >
#include < numeric >
#include < functional >
#include < climits >
using namespace std;
int n; // n : 顶点个数
vector < vector < int > > g; // g : 图(graph)(用邻接矩阵(adjacent matrix)表示)
vector < bool > known; // known : 各点是否已经选取
vector < int > dist; // dist : 已选取点集到未选取点的最小边长
vector < int > prev; // prev : 最小生成树中各点的前一顶点
int s; // s : 起点(start)
int sum; // sum : 最小生成树长
bool Prim() // 贪心算法(Greedy Algorithm)
{
known.assign(n, false);
dist.assign(n, INT_MAX);
prev.resize(n); // 初始化known、dist、prev。
dist[s] = 0; // 初始化起点到自身的路径长为0。
int i;
for (i = 0; i < n; ++i)
{
int min = INT_MAX, v;
for (int i = 0; i < n; ++i)
if (!known[i] && min > dist[i])
min = dist[i], v = i; // 寻找未知的最短路径长的顶点v,
if (min == INT_MAX) break; // 如果找不到,退出;
known[v] = true; // 如果找到,将顶点v设为已知,
sum += dist[v]; // 调整最小生成树长
for (int w = 0; w < n; ++w) // 遍历所有v指向的顶点w,
if (!known[w] && g[v][w] < INT_MAX && dist[w] > g[v][w])
dist[w] = g[v][w], prev[w] = v; // 调整顶点w的最短路径长dist和最短路径的前一顶点 prev。
}
return i == n; // 如果选取顶点个数为n,成功。
}
int main()
{
n = 7;
g.assign(n, vector<int>(n, INT_MAX));
g[0][1] = g[1][0] = 2; g[0][2] = g[2][0] = 4; g[0][3] = g[3][0] = 1;
g[1][3] = g[3][1] = 3; g[1][4] = g[4][1] = 10;
g[2][3] = g[3][2] = 2; g[2][5] = g[5][2] = 5;
g[3][4] = g[4][3] = 7; g[3][5] = g[5][3] = 8; g[3][6] = g[6][3] = 4;
g[4][6] = g[6][4] = 6;
g[5][6] = g[6][5] = 1;
s = 0; // 起点任选
sum = 0;
if (Prim())
{
cout << sum << endl;
for (int i = 1; i < n; ++i)
if(i != s) cout << prev[i] << "->" << i << endl;
}
else
{
cout << "Some vertex cann't be reached." << endl;
}
system("pause");
return 0;
}
/**/ /*=============================*/
/**/ /*
Write By LiveStar (2008.07.23)
*/
#include < stdio.h >
// max表示点,边的最大个数
#define max 1000
// wq表示两点的距离为无穷
#define wq 9999
// 邻接矩阵存储相应的边的权重
int mix[max][max];
// 输入并构造邻接矩阵
void input( int n, int m)
{
int i,j,sp,ep,wg;
//初始化邻接矩阵每个都是无穷大
for (i=0;i<n;i++)
for (j=0;j<n;j++)
mix[i][j]=wq;
printf("请输入边的起点、终点、权重(EX:1 2 3):\n");
for (i=0;i<m;i++)
{
scanf("%d %d %d",&sp,&ep,&wg);
//无向连通图
mix[sp][ep]=wg;
mix[ep][sp]=wg;
}
}
// 显示邻接矩阵
void output( int n, int m)
{
int i,j;
printf("\n邻接矩阵如下:\n\n");
for (i=0;i<n;i++)
{
for (j=0;j<n;j++)
printf("%d\t",mix[i][j]);
printf("\n");
}
}
// prim算法实现
void prim( int n, int r)
{
//a[max]用来存放各个点到已经标记点的集合的最短距离
int a[max];
//b[max]用来记录每个点的标记状态,false表示还没标记。
bool b[max];
int i,j,k,min;
//初始化从根节点开始
for (i=0;i<n;i++)
{
a[i]=mix[r][i];
b[i]=false;
}
b[r]=true;
printf("\n依次被标记的点及相应边的权重:\n");
printf("%d\t%d\n",r,0);
for (i=0;i<n-1;i++)//还剩n-1个点
{
k=0;
min=wq;
for (j=0;j<n;j++)
{
//第j个点到已经标记点的集合的距离最小且这个点还没有被标记
//k记录下一个将被标记的点
if (a[j]<min&&b[j]==false)
{
min=a[j];
k=j;
}
}
b[k]=true;//标记节点k
printf("%d\t%d\n",k,min);
//更新a[]里的状态,时刻保持最新的状态
//存放各个点到已经标记点的集合的最短距离
for (j=0;j<n;j++)
{
if (mix[k][j]<a[j])
{
a[j]=mix[k][j];
}
}
}
}
int main()
{
//n是点的个数 ,m是边的个数
int n,m,r;
printf("请输入点的个数和边的个数(EX:1 3):\n");
scanf("%d %d",&n,&m);
//输入并构造邻接矩阵
input(n,m);
//显示邻接矩阵
output(n,m);
while (1)
{
printf("\n请输入根节点(-1跳出):\n");
scanf("%d",&r);
if(r==-1)
break;
//prim算法实现
prim(n,r);
printf("\n\n");
}
return 0;
}