本题是 最小生成树,用prim 比较方便,用kruskal的话,我超时了,看了discuss 后才知道要用优先队列 优化。而且这题 prim 效率应该效率更高。
kruskal +优先队列
Memory: 8032K Time: 125MS
Language: C++ Result: Accepted
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int N,M,set[1021],need,num;
double vx[1001],vy[1001];
struct edge
{
int x,y;
double w;
}e[555555];
int find (int x)
{
int i,j,r;
r=x;
while(set[r]!=r)
r=set[r];
j=x;
while(j!=r)
{
i=set[j];
set[j]=r;
j=i;
}
return r;
}
void merge(int x,int y)
{
if(x>y)
set[x]=y;
else set[y]=x;
}
void insert(edge a)
{
int i;
num++;
e[num]=a;
i=num;
while(i>1 && e[i].w<e[i/2].w)
{
swap(e[i],e[i/2]);
i=i/2;
}
}
void heapify(int i)
{
int l,r,small;
l=i*2;;
r=l+1;
small=i;
if(l<=num && e[small].w>e[l].w)
small=l;
if(r<=num && e[small].w>e[r].w)
small=r;
if(i!=small)
{
swap(e[i],e[small]);
heapify(small);
}
}
edge del()
{
edge min;
min=e[1];
swap(e[1],e[num]);
num--;
heapify(1);
return min;
}
double dis(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
double kruskal()
{
int sn,sm;
double sum=0;
edge temp;
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++)
{
sn=find(i);
sm=find(j);
if(sn!=sm)
{
temp.x=i;
temp.y=j;
temp.w=dis(vx[i],vy[i],vx[j],vy[j]);
insert(temp);
}
}
for(int i=1;i<=num;i++)
{
temp=del();
sn=find(temp.x);
sm=find(temp.y);
if(sn!=sm)
{
merge(sn,sm);
sum+=temp.w;
need--;
}
if(need==0)break;
}
return sum;
}
int main()
{
int n,m,count;
double total;
while(scanf("%d%d",&N,&M) !=EOF)
{
count=0;
for(int i=1;i<=N;i++)
{
scanf("%lf%lf",&vx[i],&vy[i]);
}
for(int i=1;i<=N;i++)
set[i]=i;
for(int i=1;i<=M;i++)
{
int sn,sm;
scanf("%d%d",&n,&m);
sn=find(n);
sm=find(m);
merge(sn,sm);
}
need=-1;
for(int i=1;i<=N;i++)
{
if(set[i]==i )need++;
}
total=kruskal();
printf("%.2lf\n",total);
num=0;
}
}
直接prim算法
Memory: 8052K Time: 94MS
Language: C++ Result: Accepted
#include<iostream>
#include<cmath>
using namespace std;
double map[1001][1001];
int N,M;
double prim()
{
bool vis[1001]={0};
double lw[1001],min,sum;
int k;
for(int i=1;i<=N;i++)
lw[i]=map[1][i];
vis[1]=1;
sum=0;
for(int i=1;i<N;i++)
{
min=10000001;
for(int j=1;j<=N;j++)
if(!vis[j] && lw[j]<min)
{
min=lw[j];
k=j;
}
sum+=min;
vis[k]=1;
for(int j=1;j<=N;j++)
if( !vis[j] && map[k][j]<lw[j])
lw[j]=map[k][j];
}
return sum;
}
double dis(double x1,double y1,double x2,double y2)
{
return sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
}
int main()
{
double vx[1001],vy[1001],total;
int n,m;
while(scanf("%d%d",&N,&M) !=EOF)
{
for(int i=1;i<=N;i++)
scanf("%lf%lf",&vx[i],&vy[i]);
for(int i=1;i<=N;i++)
for(int j=i+1;j<=N;j++)
{
double temp=dis(vx[i],vy[i],vx[j],vy[j]);
map[i][j]=map[j][i]=temp;
}
for(int i=1;i<=M;i++)
{
scanf("%d%d",&n,&m);
map[n][m]=map[m][n]=0;
}
total=prim();
printf("%.2lf\n",total);
}
}
评论