题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1102
题目大意:给出一些顶点一些边,给出邻接矩阵,并且某些点已经连通,求最小生成树。
最小生成树算法基于贪心思想。
一开始设顶点集合S={},初始化所有顶点到集合S距离最小值为无穷大,置V1到集合S距离为0
(1)选入到集合S距离最小的顶点Vi
(2)更新未选入到S的顶点到S的最小距离
不断进行步骤(1)(2)直到所有顶点都被选入至集合S中
朴素prim算法O(v^2)
#include<iostream>
using namespace std;
const int maxn=105,inf=1<<30;
int Map[maxn][maxn],vis[maxn],d[maxn];
int n,q,ans;
int prim()
{
fill(vis,vis+maxn,0);//初始化每个点都未被加入到答案集合中
fill(d,d+maxn,inf);//初始化每个顶点到答案集合的最近距离
d[1]=0;//将顶点1加入到答案集合中
ans=0;//最小生成树权值
while(true)
{
int v=-1;//记录下一个将要加入答案集合的顶点
for(int i=1;i<=n;i++)//贪心选取离答案集合距离最近的顶点
if(!vis[i]&&(v==-1||d[i]<d[v])) v=i;
if(v==-1) break;//如果顶点都访问完了,那么v必然等于-1,则退出循环,算法结束
vis[v]=1;//加入答案集合
if(d[v]==inf) return -1;//存在孤立点,则不存在最小生成树
ans+=d[v];//加上权值
for(int i=1;i<=n;i++)//更新未加入答案集合的那些顶点到答案集合的最小距离
if(!vis[i]) d[i]=min(d[i],Map[v][i]);
}
return ans;
}
int main()
{
while(cin>>n)
{
fill(&Map[0][0],&Map[maxn][0],inf);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>Map[i][j],Map[j][i]=Map[i][j];
cin>>q;
while(q--)
{
int x,y;
cin>>x>>y;
Map[x][y]=Map[y][x]=0;
}
cout<<prim()<<endl;
}
return 0;
}
可以发现,复杂度之所以高是因为,每次要选出离集合距离最近的顶点都要用O(n)来扫一遍选取。如果这个步骤能快一点就好了,基于这个想法我们很快就可以想到,每个顶点到集合的距离可以用优先队列来维护,这样每次选取顶点只要O(logn)的复杂度。
#include<iostream>
#include<queue>
using namespace std;
const int maxn=105,inf=1<<30;
int Map[maxn][maxn],vis[maxn],ans,n,d[maxn];
struct node
{
int v,len;//v代表当前顶点,w代表v到答案集合的最小距离
friend bool operator <(node a,node b)
{
return a.len>b.len;
}
};
int prim()
{
priority_queue<node>q;
node t;
t.v=1;t.len=0;
q.push(t);//初始化顶点1到答案集合的距离为0,以保证第一次一定选入顶点1到答案集合中去
ans=0;
fill(vis,vis+maxn,0);
fill(d,d+maxn,inf);
while(q.size())
{
t=q.top();q.pop();//取离答案集合距离最小的顶点
if(vis[t.v]) continue;//如果已经在答案集合中则进行下一次的循环
vis[t.v]=1;//否则取顶点t.v加入到答案集合中
ans+=t.len;
for(int i=1;i<=n;i++)//更新未加入答案集合的顶点到答案集合 的距离
{
if(!vis[i]&&Map[t.v][i]<d[i])//可以更新则入队
{
node next;
next.v=i;
next.len=Map[t.v][i];
d[i]=Map[t.v][i];
q.push(next);
}
}
}
return ans;
}
int main()
{
while(cin>>n)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
cin>>Map[i][j];
int q;
cin>>q;
while(q--)
{
int x,y;
cin>>x>>y;
Map[x][y]=Map[y][x]=0;//x和y相连,那么它们之间的距离为0
}
cout<<prim()<<endl;
}
return 0;
}