POJ 2253 Frogger(最小生成樹)

    青蛙跳躍,題意大概是:青蛙從起點到終點進行一次或屢次的跳躍,屢次跳躍中確定有最大的跳躍距離。求在全部的跳躍中,最小的最大跳躍距離SF-_-(不理解?看題目吧)。算法

    能夠用最小生成樹完成。以起點爲根,生成一棵最小生成樹,直到樹裏包含了終點。spa

    或者這麼說吧,相似於Kruskal算法,咱們每次選取不成環的最小邊,直到這棵樹選取了通往終點的最小邊,那麼最後選擇的這條邊必然是在樹中最大的一條邊,並且在其他的邊中是最小的。你不會找到比這條邊小的最大距離,由於比它小的最小距離都在樹裏了,而未選取該邊前樹中不包含終點,即比該邊小的全部邊沒法到達終點。即改邊知足的兩個條件,最小,並且是起點到終點的最大距離(PS:挺繞的……)。code

    既然有思路了,能夠直接寫代碼了。先是上面的Kruskal算法(16MS):blog

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;

int root[202];
int x[202],y[202];

int find(int x)
{
    return root[x]?root[x]=find(root[x]):x;
}

bool union_set(int a,int b)
{
    a=find(a);
    b=find(b);
    if(a==b)
        return false;
    root[b]=a;
    return true;
}

struct Edge
{
    int x,y,dis;
    bool operator<(const Edge& cmp) const
    {
        return dis<cmp.dis;
    }
} edge[40000];

int main()
{
//  freopen("in.txt","r",stdin);
    int n,cas=1;
    while(~scanf("%d",&n) && n)
    {
        memset(root,0,sizeof(root));
        for(int i=1;i<=n;i++)
            scanf("%d%d",x+i,y+i);
        int index=0;
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                edge[index].x=i;
                edge[index].y=j;
                edge[index++].dis=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
            }
        }
        sort(edge,edge+index);

        int maxE=0;
        for(int i=0;i<index;i++)
        {
            if(union_set(edge[i].x,edge[i].y))
            {
                if(find(2)==find(1))
                {
                    maxE=edge[i].dis;
                    break;
                }
            }
        }
        printf("Scenario #%d\n",cas++);
        printf("Frog Distance = %.3f\n\n",sqrt((double)maxE));
    }
}

    使用並查集的Kruskal算法明顯要好寫一點。可是這題每兩點之間必然有一條邊,是一個稠密圖,Prim算法更適合一些。下面是Prim算法的代碼:string

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
using namespace std;

struct Node
{
    int k,w;
    bool operator<(const Node& cmp) const
    {
        return w>cmp.w;
    }
} p,q;

bool vis[202];
int x[202],y[202];
int first[202],vv[40001],ww[40001],nxt[40001];


int main()
{
//  freopen("in.txt","r",stdin);
    int n,cas=1;
    while(~scanf("%d",&n) && n)
    {
        priority_queue <Node> pq;
        memset(vis,0,sizeof(vis));
        memset(first,0,sizeof(first));

        for(int i=1;i<=n;i++)
            scanf("%d%d",x+i,y+i);

        int e=2;
        for(int i=1;i<=n;i++)
        {
            for(int j=i+1;j<=n;j++)
            {
                nxt[e]=first[i],vv[e]=j;
                ww[e+1]=ww[e]=(x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]);
                first[i]=e++;
                nxt[e]=first[j],vv[e]=i;
                first[j]=e++;
            }
        }

        p.k=1;
        p.w=0;
        pq.push(p);

        int maxE=0;
        while(!pq.empty())
        {
            p=pq.top();
            pq.pop();
            maxE=max(maxE,p.w);
            if(p.k==2)
                break;
            if(vis[p.k])
                continue;
            vis[p.k]=true;

            for(int e=first[p.k];e;e=nxt[e]) if(!vis[vv[e]])
            {
                q.k=vv[e];
                q.w=ww[e];
                pq.push(q);
            }
        }

        printf("Scenario #%d\n",cas++);
        printf("Frog Distance = %.3f\n\n",sqrt((double)maxE));
    }
}

    須要注意的是Kruskal算法最終的斷定是起點和終點是否同一集合,若是是,最大距離就是最後一條邊的距離。而prim算法的最大邊須要實時更新,由於先選的邊可能大於後來選擇的邊。搞笑的是Prim算法也是16MS,不知道是否是我寫的效率有問題SF0_0。夜深人靜的時候在去跑跑吧……it

相關文章
相關標籤/搜索