传送门:http://acm.hnu.cn/online/?action=problem&type=show&id=12126&courseid=196
裸的最小生成树。其中还有到了一条性质,就是本题中,最小生成树不可能有交叉。
证:
如果有交叉,比如上图的AC和BD,因为AE+ED>AD,BE+EC>BC,那么加上AD和BC后去掉AC和BD将得到一棵更小的树。所以这不可能是最小生成树。
这里我用的是prim算法,下面列出了两种实现:
1.朴素实现,通过数组dist[i]存储非树T内节点i到树T的最小距离,每次加入新节点时更新一次。bool数组vis[i]=true代表该点在树中。复杂度Θ(n^2)。
2.通过基于最小二叉堆的优先队列来实现。P类表示点,数据成员dist是该点到树的最短距离,id表示该点的序号。复杂度算了下貌似是O(n^2*lgn)。不是优化吗?复杂度怎么还大了。。。
1.125ms 2.140ms 果然。。。
推荐读物:《算法导论》,Thomas H.Cormen等。
CODE1:
//mst O(n^2)
#include<iostream>
#include<memory.h>
#include<cmath>
#include<fstream>
#include<iomanip>
using namespace std;
double map[1001][1001];
int N,num;
int coo[1001][2];
bool vis[1001];
double dist[1001];
double ans;
int main()
{
//ifstream cin("in1.txt");
//ofstream cout("out1.txt");
while(cin>>N&&N)
{
memset(vis,false,sizeof(vis));
ans=num=0;
for(int i=1;i<=N;i++)
cin>>coo[i][0]>>coo[i][1];
for(int i=1;i<=N;i++)
for(int j=i;j<=N;j++)
map[j][i]=map[i][j]=sqrt((coo[i][0]-coo[j][0])*(coo[i][0]-coo[j][0])+(coo[i][1]-coo[j][1])*(coo[i][1]-coo[j][1]));
int minid;
double min;
vis[1]=true;
num++;
for(int i=2;i<=N;i++)
dist[i]=map[1][i];
while(num<N)
{
min=10000000.0;
for(int i=1;i<=N;i++)
if(!vis[i]&&dist[i]<min)
{
min=dist[i];
minid=i;
}
ans+=min;
vis[minid]=true;
num++;
for(int i=1;i<=N;i++)
if(!vis[i]&&map[minid][i]<dist[i])
dist[i]=map[minid][i];
}
cout<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<endl;
}
return 0;
}
CODE2:
#include<iostream>
#include<cmath>
#include<fstream>
#include<iomanip>
using namespace std;
class P
{
public:
int id;
double dist;
};
int N,heap_size;
P A[1001];
double map[1001][1001];
int coo[1001][2];
double ans;
void Min_heapify(int i)
{
int l=i<<1;
int r=(i<<1)+1;
int min=i;
if(l<=heap_size&&A[l].dist<A[min].dist)
min=l;
if(r<=heap_size&&A[r].dist<A[min].dist)
min=r;
if(A[min].dist==A[i].dist)
return;
else
{
double t1=A[i].dist;
int t2=A[i].id;
A[i].dist=A[min].dist;
A[i].id=A[min].id;
A[min].dist=t1;
A[min].id=t2;
Min_heapify(min);
}
}
void Build_min_heap()
{
for(int i=heap_size/2;i>=1;i--)
Min_heapify(i);
}
P Heap_extract_min()
{
P min;
min.dist=A[1].dist;
min.id=A[1].id;
A[1].dist=A[heap_size].dist;
A[1].id=A[heap_size].id;
heap_size--;
Min_heapify(1);
return min;
}
void Min_decrease_key(int i,double key)
{
A[i].dist=key;
while(i>1&&A[i/2].dist>A[i].dist)
{
double t1=A[i].dist;
int t2=A[i].id;
A[i].dist=A[i/2].dist;
A[i].id=A[i/2].id;
A[i/2].dist=t1;
A[i/2].id=t2;
i=i/2;
}
}
int main()
{
//ifstream cin("in1.txt");
while(cin>>N&&N)
{
heap_size=N-1;
ans=0;
for(int i=1;i<=N;i++)
cin>>coo[i][0]>>coo[i][1];
for(int i=1;i<=N;i++)
for(int j=i;j<=N;j++)
map[j][i]=map[i][j]=sqrt((coo[i][0]-coo[j][0])*(coo[i][0]-coo[j][0])+(coo[i][1]-coo[j][1])*(coo[i][1]-coo[j][1]));
for(int i=2;i<=N;i++)
{
A[i-1].dist=map[i][1];
A[i-1].id=i;
}
Build_min_heap();
while(heap_size>0)
{
P t=Heap_extract_min();
ans+=t.dist;
for(int i=1;i<=heap_size;i++)
if(map[A[i].id][t.id]<A[i].dist)
Min_decrease_key(i,map[A[i].id][t.id]);
}
cout<<setiosflags(ios::fixed)<<setprecision(2)<<ans<<endl;
}
return 0;
}