zoukankan      html  css  js  c++  java
  • 【BZOJ-4456】旅行者 分治 + 最短路

    4456: [Zjoi2016]旅行者

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 254  Solved: 162
    [Submit][Status][Discuss]

    Description

    小Y来到了一个新的城市旅行。她发现了这个城市的布局是网格状的,也就是有n条从东到西的道路和m条从南到北的道路,这些道路两两相交形成n×m个路口 (i,j)(1≤i≤n,1≤j≤m)。她发现不同的道路路况不同,所以通过不同的路口需要不同的时间。通过调查发现,从路口(i,j)到路口(i,j+1)需要时间 r(i,j),从路口(i,j)到路口(i+1,j)需要时间c(i,j)。注意这里的道路是双向的。小Y有q个询问,她想知道从路口(x1,y1)到路口(x2,y2)最少需要花多少时间。

    Input

    第一行包含 2 个正整数n,m,表示城市的大小。
    接下来n行,每行包含m?1个整数,第i行第j个正整数表示从一个路口到另一个路口的时间r(i,j)。
    接下来n?1行,每行包含m个整数,第i行第j个正整数表示从一个路口到另一个路口的时间c(i,j)。
    接下来一行,包含1个正整数q,表示小Y的询问个数。
    接下来q行,每行包含4个正整数 x1,y1,x2,y2,表示两个路口的位置。

    Output

    输出共q行,每行包含一个整数表示从一个路口到另一个路口最少需要花的时间。

    Sample Input

    2 2
    2
    3
    6 4
    2
    1 1 2 2
    1 2 2 1

    Sample Output

    6
    7

    HINT

    Source

    Solution

    分治每次求起点和终点都在[xl,xr],[yl,yr]的答案。

    考虑对这个大矩形进行分割。

    把比较短的一维切成两半,并枚举切割的这条中线上的所有点,并从这些点向其余各点求最短路。然后用最短路得到的答案去更新答案。然后递归分治;

    分析一下复杂度:$logN$的分治,因为每次切较短边,所以复杂度最多不超过$sqrt{N}$,最后还有Dijskra的$NlogN$

    个人感觉大概是$O(Nsqrt{N}log^{2}N)$的复杂度,但是,网上有严格的证明复杂度,是$O(Nsqrt{N}logN)$的,并不是很会,戳这里吧

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue>
    #include<vector>
    using namespace std;
    inline int read()
    {
        int x=0; char ch=getchar();
        while (ch<'0' || ch>'9') {ch=getchar();}
        while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
        return x;
    }
    #define MAXN 20010
    int N,M,Q,tp;
    vector<int>id[MAXN];
    struct EdgeNode{int next,to,d;}edge[MAXN<<2];
    int head[MAXN],cnt=1;
    inline void AddEdge(int u,int v,int w) {cnt++; edge[cnt].next=head[u]; head[u]=cnt; edge[cnt].to=v; edge[cnt].d=w;}
    inline void InsertEdge(int u,int v,int w) {AddEdge(u,v,w); AddEdge(v,u,w);}
    #define Pa pair<int,int>
    #define INF 0x7fffffff
    priority_queue<Pa,vector<Pa>,greater<Pa> >q;
    int dis[MAXN],X[MAXN],Y[MAXN];
    bool visit[MAXN];
    inline void Dijkstra(int S,int xl,int xr,int yl,int yr)
    {
        for (int i=xl; i<=xr; i++)
            for (int j=yl; j<=yr; j++)
                dis[id[i][j]]=INF;
        q.push(make_pair(0,S)); dis[S]=0;
        while (!q.empty())
            {
                int now=q.top().second;
                int Dis=q.top().first;
                q.pop();
                if (Dis>dis[now]) continue;
                for (int i=head[now]; i; i=edge[i].next)
                    if (X[edge[i].to]<xl || X[edge[i].to]>xr || Y[edge[i].to]<yl || Y[edge[i].to]>yr) continue;
                        else
                            if (Dis + edge[i].d < dis[edge[i].to])
                                dis[edge[i].to]=Dis+edge[i].d,
                                q.push(make_pair(dis[edge[i].to],edge[i].to));
            }
    //    puts("DIS");
    //    for (int i=xl; i<=xr; i++)
    //      for (int j=yl; j<=yr; j++)
    //          printf("%d  ",dis[id[i][j]]);
    //    puts("");
    }
    #define MAXQ 100010
    int ans[MAXQ];
    struct AskNode{int x0,y0,x1,y1,id,u,v;}ask[MAXQ],tmp[MAXQ];
    void CDQ(int xl,int xr,int yl,int yr,int ql,int qr)
    {
        if (ql>qr) return;
        bool f=0; int l,r;
        if (xr-xl<yr-yl) l=yl,r=yr,f=1; else l=xl,r=xr,f=0;
        int mid=(l+r)>>1;
    //  printf("CDQ(%d,%d,%d,%d,%d,%d,%d)
    ",xl,xr,yl,yr,ql,qr,mid);
        if (f)
            for (int i=xl; i<=xr; i++)
                {
                    Dijkstra(id[i][mid],xl,xr,yl,yr);
                    for (int j=ql; j<=qr; j++)
                        ans[ask[j].id]=min(ans[ask[j].id],dis[ask[j].u]+dis[ask[j].v]);
                }
        else
            for (int i=yl; i<=yr; i++)
                {
                    Dijkstra(id[mid][i],xl,xr,yl,yr);
                    for (int j=ql; j<=qr; j++)
                        ans[ask[j].id]=min(ans[ask[j].id],dis[ask[j].u]+dis[ask[j].v]);
                }
        int L=ql-1,R=qr+1;
        for (int i=ql; i<=qr; i++)
            if (f) 
                if (ask[i].y0<mid && ask[i].y1<mid) tmp[++L]=ask[i]; else if (ask[i].y0>mid && ask[i].y1>mid) tmp[--R]=ask[i]; else;
            else
                if (ask[i].x0<mid && ask[i].x1<mid) tmp[++L]=ask[i]; else if (ask[i].x0>mid && ask[i].x1>mid) tmp[--R]=ask[i]; else;
        for (int i=ql; i<=L; i++) ask[i]=tmp[i];
        for (int i=R; i<=qr; i++) ask[i]=tmp[i];
        if (f) CDQ(xl,xr,yl,mid-1,ql,L),CDQ(xl,xr,mid+1,yr,R,qr);
          else CDQ(xl,mid-1,yl,yr,ql,L),CDQ(mid+1,xr,yl,yr,R,qr);
    }
    int main()
    {
        N=read(),M=read();
        for (int i=1; i<=N; i++) id[i].push_back(0);
        for (int i=1,ID=0; i<=N; i++)
            for (int j=1; j<=M; j++)
                id[i].push_back(++ID),X[ID]=i,Y[ID]=j;
        for (int i=1,len; i<=N; i++)
            for (int j=1; j<=M-1; j++)
                len=read(),InsertEdge(id[i][j],id[i][j+1],len);
        for (int i=1,len; i<=N-1; i++)
            for (int j=1; j<=M; j++)
                len=read(),InsertEdge(id[i][j],id[i+1][j],len);
        Q=read();
        while (Q--)
            {
                tp++; ask[tp].id=tp;
                ask[tp].x0=read(); ask[tp].y0=read(); ask[tp].u=id[ask[tp].x0][ask[tp].y0];
                ask[tp].x1=read(); ask[tp].y1=read(); ask[tp].v=id[ask[tp].x1][ask[tp].y1];
                if (ask[tp].u==ask[tp].v) ans[tp]=0; else ans[tp]=INF;
            }
        CDQ(1,N,1,M,1,tp);
        for (int i=1; i<=tp; i++) printf("%d
    ",ans[i]);
        return 0;
    }

    UOJ只能跑过50分,BZOJ 17sAC....

    比别人慢很多,于是试了试spfa,然后...UOJ40,BZOJ TLE

    BZOJ  Dijsktra与spfa的对比:

  • 相关阅读:
    独立思考模型与经验-仅供参考
    独立思考与输入、吸收
    基于事实和全方位思考
    独立思考有四个层次-知识体系
    思维框架
    阅读、思考与吸收
    思考与阅读
    博学之,审问之,慎思之,明辨之,笃行之:思考与成长
    如何成为有想法的人?如何培养独立思考的能力?
    人的本质--以人为本--思考-认识世界、改造世界
  • 原文地址:https://www.cnblogs.com/DaD3zZ-Beyonder/p/5865813.html
Copyright © 2011-2022 走看看