• 循环队列+堆优化dijkstra最短路 BZOJ 4152: [AMPPZ2014]The Captain


    循环队列基础知识

    1.循环队列需要几个参数来确定

    循环队列需要2个参数,front和rear

    2.循环队列各个参数的含义

    (1)队列初始化时,front和rear值都为零;

    (2)当队列不为空时,front指向队列的第一个元素,rear指向队列最后一个元素的下一个位置;

    (3)当队列为空时,front与rear的值相等,但不一定为零;

    3.循环队列入队的伪算法

    (1)把值存在rear所在的位置;

    (2)rear=(rear+1)%maxsize ,其中maxsize代表数组的长度;

    4.循环队列出队的伪算法

    (1)先保存出队的值;

    (2)front=(front+1)%maxsize ,其中maxsize代表数组的长度;

    5.如何判断循环队列是否为空

    if(front==rear)

        队列空;

    else

        队列不空;

    6.如何判断循环队列是否为满?

    这个问题比较复杂,假设数组的存数空间为7,此时已经存放1,a,5,7,22,90六个元素了,如果在往数组中添加一个元素,则rear=front;此时,队列满与队列空的判断条件front=rear相同,这样的话我们就不能判断队列到底是空还是满了;

    解决这个问题有两个办法:一是增加一个参数,用来记录数组中当前元素的个数;第二个办法是,少用一个存储空间,也就是数组的最后一个存数空间不用,当(rear+1)%maxsiz=front时,队列满;

    例题:

    4152: [AMPPZ2014]The Captain

    Time Limit: 20 Sec  Memory Limit: 256 MB
    Submit: 664  Solved: 256
    [Submit][Status][Discuss]

    Description

    给定平面上的n个点,定义(x1,y1)到(x2,y2)的费用为min(|x1-x2|,|y1-y2|),求从1号点走到n号点的最小费用。

    Input

    第一行包含一个正整数n(2<=n<=200000),表示点数。
    接下来n行,每行包含两个整数x[i],y[i](0<=x[i],y[i]<=10^9),依次表示每个点的坐标。
     
     

    Output

    一个整数,即最小费用。

    Sample Input

    5
    2 2
    1 1
    4 5
    7 1
    6 7

    Sample Output

    2
    首先,我们可以无视min,直接两点之间建一条|x2-x1|的边和一条|y2-y1|的边
    可以发现,对于点(x1,y1),(x2,y2),(x3,y3),x1<x2<x3,则|x2-x1|+|x3-x2| = |x3-x1|
    所以从x1连向x3用x坐标计算权值的边是没有用的。
    Y同理
    所以每个点只需要向上下左右最靠近的点连边,排序即可
    先按x排序, 然后只有相邻节点的边才有用, 我们连起来, 再按y排序做相同操作...然后就跑dijikstra,这个题目是卡spfa的。
    而且dijistra不用队优化会超时的。呵呵~。
      1 #include<cstring>
      2 #define N 200010
      3 #define inf (unsigned long long)((1<<63)-1)/*直接复制(1<<63)-1是会出现-1的,在前面要有ull*/
      4 #include<iostream>
      5 using namespace std;
      6 #include<cstdio>
      7 #include<cstdlib>
      8 #include<queue>
      9 #include<cmath>
     10 #include<algorithm>
     11 struct Edge{
     12     int v,last;
     13     unsigned long long w;
     14 }edge[N<<2];
     15 struct Jg{
     16     int x,y;
     17 }dian[N];
     18 int head[N],X[N],Y[N],n,t=0;
     19 unsigned long long dis[N];
     20 struct Dis{
     21     int id;
     22     unsigned long long d;
     23     Dis(){d=inf;}
     24     bool operator <(Dis K)
     25     const{return d>K.d;    }/*优先队列是默认大的元素在前,这个重载运算符只能对<,把他变成>即可*/
     26 };
     27 priority_queue<Dis>Q;
     28 bool vis[N]={false};
     29 inline int read()
     30 {
     31     int ret=0,ff=1;
     32     char s=getchar();
     33     while(s<'0'||s>'9')
     34     {
     35         if(s=='-') ff=-1;
     36         s=getchar();
     37     }
     38     while(s>='0'&&s<='9')
     39     {
     40         ret=ret*10+s-'0';
     41         s=getchar();
     42     }
     43     return ret*ff;
     44 }
     45 void input()
     46 {
     47     n=read();
     48     for(int i=1;i<=n;++i)
     49     {
     50        dian[i].x=read();dian[i].y=read();
     51        X[i]=Y[i]=i;    
     52     }
     53 }
     54 bool cmpx(int a,int b)/*排序,a,b代表X[N]数组中的某两个元素,他们代表的是dian数组的编号*/
     55 {
     56     return dian[a].x<dian[b].x;
     57 }
     58 bool cmpy(int a,int b)
     59 {
     60     return dian[a].y<dian[b].y;
     61 }
     62 void add_edge(int a,int b,int falgg)
     63 {
     64     if(falgg==1)
     65     {
     66         ++t;
     67         edge[t].v=b;
     68         edge[t].w=abs(dian[a].x-dian[b].x); 
     69         edge[t].last=head[a];
     70         head[a]=t;
     71     }
     72     else 
     73     {
     74         ++t;
     75         edge[t].v=b;
     76         edge[t].w=abs(dian[a].y-dian[b].y);
     77         edge[t].last=head[a];
     78         head[a]=t;
     79     }
     80 }
     81 void build_line()
     82 {/*先按x排序, 然后只有相邻节点的边才有用, 我们连起来, 再按y排序做相同操作.*/
     83     sort(X+1,X+n+1,cmpx);
     84     for(int i=2;i<=n;++i)
     85     {
     86         add_edge(X[i],X[i-1],1);
     87         add_edge(X[i-1],X[i],1);
     88     }
     89     sort(Y+1,Y+n+1,cmpy);
     90     for(int i=2;i<=n;++i)
     91     {
     92         add_edge(Y[i],Y[i-1],2);
     93         add_edge(Y[i-1],Y[i],2);
     94     }
     95 }
     96 void dijkstra()
     97 {
     98     for(int i=1;i<=n;++i)
     99       dis[i]=inf;
    100     dis[1]=0;
    101     Dis now;
    102     now.id=1;now.d=0;
    103     Q.push(now);
    104     while(!Q.empty())
    105     {
    106         Dis nowe=Q.top();
    107         Q.pop();
    108         if(dis[nowe.id]!=nowe.d)continue;
    109         if(vis[nowe.id])continue;
    110         vis[nowe.id]=true;
    111         for(int l=head[nowe.id];l;l=edge[l].last)
    112         {
    113             if(!vis[edge[l].v]&&dis[edge[l].v]>dis[nowe.id]+edge[l].w)
    114             {
    115                 dis[edge[l].v]=dis[nowe.id]+edge[l].w;
    116                 Dis now;
    117                 now.id=edge[l].v;now.d=dis[edge[l].v];
    118                 Q.push(now);
    119             }
    120         }
    121     }
    122 }
    123 int main()
    124 {
    125     input();
    126     build_line();
    127     dijkstra();
    128     cout<<dis[n];
    129     return 0;
    130 }
  • 相关阅读:
    Oracle数据库基础select语句用法
    Java中volatile的作用以及用法
    [Java]读取文件方法大全
    经典SQL语句大全
    js动态加载控件jsp页面
    JAVA中List、Map、Set的区别与选用
    表格java代码的相关知识积累
    解决JSP中文乱码问题
    SSH框架的简单学习—Structs学习
    float存储方式编程验证
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5804697.html
Copyright © 2020-2023  润新知