BZOJ 4152 The Captain

来源:互联网 发布:求一些莆田鞋的淘宝店 编辑:程序博客网 时间:2024/05/19 15:43

思路、证明什么的都在代码的注释里。


需要说明的一点是STL堆默认为大顶堆,一定要记住。。。。


#include<iostream>#include<cstring>#include<cstdlib>#include<cstdio>#include<queue>#include<algorithm> using namespace std; const int maxn=200005<<1; typedef pair<int,int> node; struct edge{    int to,next;    long long val;}e[maxn<<1]; struct point{    int x,y,id;}p[maxn]; int n,cnt;int head[maxn];bool vst[maxn];long long dist[maxn]; void insert(int a,int b,long long val){    e[++cnt].val=val;e[cnt].to=b;e[cnt].next=head[a];head[a]=cnt;}bool cmp1(point a,point b){    return a.x<b.x;}bool cmp2(point a,point b){    return a.y<b.y;}void dijkstra(){    priority_queue< node,vector<node>,greater<node> >q;    memset(dist,0x3f,sizeof dist);    dist[1]=0;    q.push((node){0,1});    while(!q.empty())    {        int u=q.top().second;        q.pop();        if(vst[u])continue;        vst[u]=true;        for(int i=head[u];i;i=e[i].next)        {            int v=e[i].to;            if(dist[v]>dist[u]+e[i].val)            {                dist[v]=dist[u]+e[i].val;                q.push((node){dist[v],v});            }        }    }     printf("%lld",dist[n]);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)    {        scanf("%d%d",&p[i].x,&p[i].y);        p[i].id=i;    }    //假设他们相邻,则两点A、B之间连边一定是最优解    //假设他们y方向相邻,x方向上有一中间点C,那么可以确定如果A,B通过x方向得到的答案必不差于经过C//假设通过y方向直接连比经过C优,这是可以做到的,然而y方向上A,B两点已连,所以如此连边可以保证答案正确//假设A,B y方向上中间还有D点间隔,那么A,B无法连边,现在考虑A,B无法连边对答案的影响//假设A,B直接连严格更优,那么 必然是通过x,y其中一个方向实现的,然而可以确定这两个方向绕过C或D必不比直接连边更差//由此假设不成立,所以A,B不连边对答案无影响,由此保证了答案的正确性     sort(p+1,p+n+1,cmp1);    for(int i=2;i<=n;i++)    {        insert(p[i].id,p[i-1].id,p[i].x-p[i-1].x);        insert(p[i-1].id,p[i].id,p[i].x-p[i-1].x);        //因为不知要向那个方向,所以双向连边,至少要用到一条     }    sort(p+1,p+n+1,cmp2);    for(int i=2;i<=n;i++)    {        insert(p[i].id,p[i-1].id,p[i].y-p[i-1].y);        insert(p[i-1].id,p[i].id,p[i].y-p[i-1].y);    }    dijkstra();    return 0;}