题目:
当N为0时输入结束。
3 1 2 1 0 1 3 2 0 2 3 4 0 3 1 2 1 0 1 3 2 0 2 3 4 1 3 1 2 1 0 1 3 2 1 2 3 4 1 0
3 1 0
Krustal算法:
#include<iostream>
#include<limits>
#include<vector>
#include<algorithm>
using namespace std;
const int MAX=100;
const int INF=INT_MAX;
int parent[MAX];
int height[MAX];
int N=0;
struct Edge
{
int begin;
int end;
int cost;
};
vector<Edge> edgeArr;
vector<Edge>::iterator iter;
//比较边大小函数
bool cmp(Edge e1, Edge e2)
{
bool flag=false;
if(e1.cost < e2.cost)
flag=true;
else if(e1.cost == e2.cost)
{
if(e1.begin < e2.begin)
flag=true;
else if(e1.begin == e2.begin && e1.end < e2.end)
flag=true;
}
return flag;
}
//查找根
int find(int x)
{
if(parent[x] != x)
parent[x]=find(parent[x]);
return parent[x];
}
//合并
void merge(int x, int y)
{
int rx=find(x);
int ry=find(y);
if(height[rx] < height[ry])
parent[rx]=ry;
else
{
parent[ry]=rx;
if(height[rx] == height[ry])
height[rx]++;
}
}
//初始化并查集数组
void init()
{
for(int i=1;i<=N;i++)
{
parent[i]=i;
height[i]=1;
}
}
//读取边信息
void readEdge()
{
int begin, end, cost, path;
edgeArr.clear();
for(int i=1;i<=N*(N-1)/2;i++)
{
//cin>>begin>>end>>cost>>path;
scanf("%d %d %d %d",&begin,&end,&cost,&path);
if(path)
cost=0;
Edge edge;
edge.begin=begin;
edge.end=end;
edge.cost=cost;
edgeArr.push_back(edge);//保存边到向量中
}
}
//Krustal算法求最小生成树
int krustal()
{
int mincost=0;
//排序,依次添加最小边
std::sort(edgeArr.begin(), edgeArr.end(), cmp);
init();
int begin ,end, cost;
iter=edgeArr.begin();
int count=0;
while(count != N-1 && iter != edgeArr.end())
{
//读取边的信息
begin=iter->begin;
end=iter->end;
cost=iter->cost;
if(find(begin) != find(end))//不在同一个连通分量,可以添加而不会构成环
{
count++;
mincost+=cost;
merge(begin, end);//合并
}
iter++;
}
return mincost;
}
int main()
{
scanf("%d", &N);
while(N != 0)
{
readEdge();
cout<<krustal()<<endl;
scanf("%d", &N);
}
return 0;
}
Prim算法
#include<iostream>
#include<limits>
#include<vector>
#include<algorithm>
using namespace std;
const int MAX=100;
const int INF=INT_MAX;
int costArr[MAX][MAX];
int mark[MAX];
int minCost[MAX];
int N;
//初始化
void init()
{
for(int i=1;i<=N;i++)
costArr[i][i]=0;
for(int i=1;i<=N;i++)
{
mark[i]=0;
minCost[i]=INF;
}
mark[1]=1;
minCost[1]=0;
}
//读取边信息
void readEdge()
{
int begin, end, cost, path;
for(int i=1;i<=N*(N-1)/2;i++)
{
scanf("%d %d %d %d",&begin,&end,&cost,&path);
if(path)
cost=0;
costArr[begin][end]=costArr[end][begin]=cost;
}
}
int prim()
{
init();
int i=1;
int count=1;
//prim算法,更新当前U中点到V-U距离
while(count < N)
{
for(int j=1;j <= N; j++)
{
if(!mark[j] && costArr[i][j] < minCost[j])//更新最小值
{
minCost[j]=costArr[i][j];
}
}
//查找要添加到U中的点
int min=INF;
for(int j=1;j <= N; j++)
{
if(!mark[j] && minCost[j] < min)
{
min=minCost[j];
i=j;
}
}
mark[i]=1;
count++;
}
//计算最小值
int sumcost=0;
for(int i=1; i<=N;i++)
{
sumcost+=minCost[i];
}
return sumcost;
}
int main()
{
while(cin>>N, N != 0)
{
readEdge();
cout<<prim()<<endl;
}
return 0;
}
测试数据:
4
1 2 4 0
1 3 9 0
1 4 21 0
2 3 8 0
2 4 17 0
3 4 16 0
答案:28