代码如下:
#include<fstream>
#define MAXN 100
using namespace std ;
ifstream cin("test.txt") ;
ofstream cout("MST.out") ;
const int infinity = 1000000 ;
int cost[MAXN][MAXN],g[MAXN][MAXN],n,m=0;
int dis[MAXN],f[MAXN],w[MAXN],u[MAXN],v[MAXN],vis[MAXN];
//u,v,w数组分别表示边的起始点,终止点,和权值
//f用做并查集,vis用来记录dfs时某点是否被访问过
int prim(int v0)
{
int i,j,distance,k;
int ans = 0;
for(i = 0;i < n;i++)
dis[i] = cost[v0][i]; //dis[i]表示所有与i相连的边中,权值最小的那个
for(i = 0;i < n-1; i++)
{
distance = infinity;
for(j = 0;j < n; j++)
if(dis[j] && distance > dis[j])
{ //在所有U集合和V-U集合的连边中选出最小一条
distance = dis[j];
k = j;
}
ans += dis[k];
dis[k] = 0; //k节点加入集合U
for(j = 0;j < n;j++)
if(cost[j][k] < dis[j])
dis[j] = cost[j][k];
}
return ans;
}
void sort() //普通的排序O(m^2),用快排可使时间复杂度均摊为O(mlogm).
{
for (int i = 1 ; i<=m ; i++)
for (int j = i+1 ; j<=m ; j++)
if (w[i]>w[j])
{
int tmp = w[i] ; w[i] = w[j]; w[j] = tmp ;
tmp = u[i] ; u[i] = u[j]; u[j] = tmp ;
tmp = v[i] ; v[i] = v[j]; v[j] = tmp ;
}
}
int find(int i) //并查集,查找父亲
{
if ( f[i]!=i ) f[i]=find( f[i] ) ; //路径压缩
return f[i] ;
}
void Union(int i,int j) //两个并查集的合并
{
i=find( i ) ;
j=find( j ) ;
if (i != j ) f[j] = i ;
}
int Kruskal()
{
int total=0 , answer = 0 ; //total表示边数,当边数为n-1时,算法结束
sort();
for (int i=1 ; i<=m ; i++) cout << w[i] << endl ;
for (int i=0 ; i<n ; i++) f[i] = i;
for (int i = 1 ; i<= m ; i++)
if ( find(u[i]) != find(v[i]) ) //用并查集判断两个节点是否在同一个集合中
{
Union(u[i],v[i]) ;
answer = answer + w[i] ;
++ total ;
if (total == n-1 ) break ;
}
return answer ;
}
void dfs(int u) //图的深度优先遍历
{
vis[u] = 1 ;
for (int i = 0 ; i<n ; i++)
if ( ( g[u][i]!=infinity ) && !vis[i] ) dfs(i) ;
}
bool QuBian(int th) //判断去掉第th条边后图还能不能连通
{
g[ u[th] ][ v[th] ] = infinity ;
g[ v[th] ][ u[th] ] = infinity ;
for(int i=0; i<n ;i++) vis[i]=0;
dfs(u[th]);
int total = 0 ;
for (int i = 0 ; i<n ; i++)
if (vis[i]) ++total ;
if ( total==n ) return true ;
else return false ;
}
int work()
{
int answer = 0 ; //answer表示最终结果
int t1=0,t2=0 ; //t1表示去掉的边数,t2表示保留的边数
for (int i=0 ; i<n ; i++)
for (int j=0 ; j<n ; j++) g[i][j] = cost[i][j] ;
int k;
for ( k=m ; k>0 ; k--) //k表示当前图中剩下的边数
if ( !QuBian(k) )
{
g[ u[k] ][ v[k] ] = w[k] ;
g[ v[k] ][ u[k] ] = w[k] ;
++t1 ;
answer += w[k] ;
if (t1+k == n-1 ) break ;
} //当图中剩下的边数和保留的边数之和为n-1时,不再去边
else ++t2;
for (int j=k ; j>0 ; j--) answer+=w[j] ;
return answer ;
}
int main(){
cin >> n >> m;
for (int i=0 ; i<n ; i++)
for (int j=0 ; j<n ; j++)
cost[i][j] = infinity ;
for (int i=1 ; i<=m ; i++)
{
cin >> u[i] >> v[i] >> w[i] ;
cost[u[i]][v[i]] = w[i] ;
cost[v[i]][u[i]] = w[i] ;
}
cout << prim(0) << endl;
cout << Kruskal() << endl;
cout << work() << endl;
return 0 ;
}