2010 Mid-Atlantic Regional Programming Contest H题 Underground Cables 分析&解题报告


传送门: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值