正文

PKU 36252009-11-24 19:51:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/hujixiang/50169.html

分享到:

本题是 最小生成树,用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);
  }

}

阅读(2292) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册