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

来源:互联网 发布:mysql updata 编辑:程序博客网 时间:2024/05/16 05:12


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


原创粉丝点击