2017年广东ACM省赛 I题 解题报告

题意:

平面上有n个点,已知每个点的坐标(xi, yi),找出n-1条边使得n个点连通。求出这n-1条边的最小长度和。


这题明显是求最小生成树,但是点数n高达10^5,用传统的Krustal或Prim算法都会超时。这时需要更加高效的算法,用一种称为“三角剖分”的方法来优化。

其实我也不懂什么是“三角剖分”,但是查到有原题,BZOJ4129,只是题目描述背景改变了而已。

下面是BZOJ 4129的代码(引用自http://blog.csdn.net/liutian429073576/article/details/52141164)

#include
#include
#include
#include
#include
#include
using namespace std;
#define New(a,b) __typeof__(b) a=(b)
#define x first
#define y second
#define ld double 
const
    double eps=1e-8;
struct point
{
    ld x,y;
    point(){}
    point(ld x,ld y):x(x),y(y){}
    inline point operator+(point z){return point(x+z.x,y+z.y);}
    inline point operator-(point z){return point(x-z.x,y-z.y);}
    inline point operator*(ld z){return point(x*z,y*z);}
    inline point operator/(ld z){return point(x/z,y/z);}
    inline ld operator*(point z){return x*z.x+y*z.y;}
    inline ld operator^(point z){return x*z.y-y*z.x;}
    inline bool operator<(point z)const{return abs(x-z.x)i.T;}
};
priority_queueevent;
#define sqr(x)  ((x)*(x))
inline void add(int x,int y,int z)
{
    point a=p[x],b=p[y],c=p[z];
    point v=c-b,w=a-b;
    ld d=w^v;
    if(dAll;
inline bool cmp(int a,int b){return p[a] >ed[1000001];
int edn;
inline void Pre()
{
    for(int i=0;ip[pos[i]].x+eps)break;
            ev x=event.top();event.pop();
            swp=(x.T+lst)/2;
            New(tmp,All.find(pr(x.y,x.z)));
            New(tmp0,tmp);
            if(tmp==All.end()||tmp==All.begin()||((--tmp0)->x^x.x))continue;
            New(tmp1,tmp0);
            if(tmp0!=All.begin())--tmp0,add(tmp0->x,x.x,x.z);
            if(++(tmp0=tmp)!=All.end())add(x.x,x.z,tmp0->y);
            All.erase(tmp1,tmp0);
            All.insert(pr(x.x,x.z));
            ed[edn++]=make_pair(sqr(p[x.z]-p[x.x]),make_pair(x.x,x.z));
        }
        if(i==n)break;
        lst=swp=p[pos[i]].x,curx=p[pos[i]].y;
        New(tmp,All.lower_bound(pr(-1,-1)));
        if(tmp!=All.end()&&abs(tmp->get_y(swp)-curx)x,u=tmp->y;
            New(tmp0,tmp);
            if(++tmp0!=All.end())add(pos[i],u,tmp0->y);
            if(tmp!=All.begin())
            {
                --(tmp0=tmp);
                add(tmp0->x,d,pos[i]);
            }
            All.erase(tmp);
            ed[edn++]=make_pair(sqr(p[d]-p[pos[i]]),make_pair(d,pos[i]));
            ed[edn++]=make_pair(sqr(p[pos[i]]-p[u]),make_pair(pos[i],u));
            All.insert(pr(d,pos[i]));
            All.insert(pr(pos[i],u));
        }
        else
        {
            int Mid=tmp==All.end()?pos[s-1]:tmp->x;
            if(tmp!=All.end())add(pos[i],Mid,tmp->y);
            if(tmp!=All.begin()){New(tmp0,tmp);add((--tmp0)->x,Mid,pos[i]);}
            ed[edn++]=make_pair(sqr(p[pos[i]]-p[Mid]),make_pair(pos[i],Mid));
            All.insert(pr(pos[i],Mid));
            All.insert(pr(Mid,pos[i]));
        }
    }
}
int f[100001];

struct Chain{int u;ld len;Chain*next;}*Head[100001];
inline void Add(int u,int v,ld len)
{Chain *tp=new Chain;tp->u=v;tp->len=len;tp->next=Head[u];Head[u]=tp;}


int F[109001][17];
ld Data[100001][17];
int Dep[100001];
ld Query(int u,int v)
{
    int j=16;
    ld res=0;
    if(Dep[u]=Dep[v])
            res=max(res,Data[u][j]),u=F[u][j];
        j--;
    }
    j=16;
    while(~j)
    {
        if(F[u][j]^F[v][j])res=max(res,max(Data[u][j],Data[v][j])),u=F[u][j],v=F[v][j];
        j--;
    }
    return u==v?res:max(res,max(Data[u][0],Data[v][0]));
}
char c;
inline void read(int&a)
{a=0;do c=getchar();while(c<'0'||c>'9');while(c<='9'&&c>='0')a=(a<<3)+(a<<1)+c-'0',c=getchar();}
void Reply()
{
    int n,u,v;
    read(n);
    while(n--)
    {
        read(u),read(v);
        u--,v--;
        printf("%.6f\n",Query(u,v));
    }
}

void DFS(int u)
{
    for(int i=1;i<=16;i++)
        F[u][i]=F[F[u][i-1]][i-1],
    Data[u][i]=max(Data[u][i-1],Data[F[u][i-1]][i-1]);
    Dep[u]=Dep[F[u][0]]+1;
    for(Chain *tp=Head[u];tp;tp=tp->next)
        if(tp->u^F[u][0])F[tp->u][0]=u,Data[tp->u][0]=tp->len,DFS(tp->u);
    if(u==F[u][0])
        Reply();
}
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
inline void kru()
{
    init();
    Pre();
    for(int i=0;i

这题应该算是模板题吧,不过比赛期间没有队伍通过这题,可见还是有一定难度的

你可能感兴趣的:(树)