[多校联考-初级]徒步旅行

丶灬走出姿态 提交于 2019-11-30 16:01:39

题目

【内存限制:$512 MiB$】  【时间限制:$2000 ms$】
【标准输入输出】  【题目类型:传统】  【评测方式:文本比较】
 
 

【题目描述】

小$A$决定开始一场奇妙的徒步旅行,旅行地图可以看成是一个平面直角坐标系,小$A$从家$O(0,0)$出发,每一步移动只能由他此时所在的位置$(x,y)$走到以下四个坐标之一:$(x-1,y),(x,y-1),(x+1,y),(x,y+1)$。现在有$N$个旅游景点,第$i$个旅游景点位置为$(x_i,y_i)$。 由于世界如此之大,整个旅行地图被分成了多个不同的气候区,某个景点$(x_i,y_i)$的气候区$C_i=max(x_i,y_i)$。小$A$想要更好的了解这个世界使得他这次徒步旅行更有意义,所以他想要去气候区$i+1$旅行当且仅当访问完气候区$i$的所有旅游景点。当他访问完所有的景点时,他会回到家里。 小$A$想让你帮他设计出一条旅游路线使得他移动的步数最少,因为徒步旅行还是比较累的……

【输入格式】

第一行输入一个整数$N$,表示旅游景点数量。

接下来$N$行,每行一个整数对$(x_i,y_i)$代表第$i$个景区的位置。

【输出格式】

仅一行,表示小$A$完成旅行所需移动的最少步数。

【数据范围】

对于所有测试数据:

$1≤n≤3 * 10^5$

$0≤h≤10^9$

$0≤x,y≤10^9$

题解

【做题经历】

这道题看到有四个方向,又是在一个网格中走路,首先我想到的就是搜索......

看了看数据范围,然后居然又想到剪枝或者是一个记忆化......

然后,$dp$思路就出来了

刚开始的$dp$思路:

定义状态$dp_{ij}$:已经访问了第$i$个气候区的其中$j$个

这个状态转移似乎很好想,但是感觉有些别扭

比如说你的上一层状态是从哪一个点转移过来的,这还是要枚举

然后就是你已经访问当前气候区的哪些点了,这个也是不知道的

所以说,这个状态定义得是有问题的

【正解】

想了一会儿,发现了一个关键的点:

 每一个气候区在网格中都是一个拐角的形状,就像这样

当然这不是我说的关键的点

而每次访问完一个气候区,总是在这个拐角的最左边或者是最下边

那么我们就可以再新定义一个状态$dp[i][0|1]$:在访问完第i个气候区之后,是在最左边$(j==0)$还是最下边$(j==1)$

将输入的数据按照气候区从小到大排序(当然还有很多细节,这个交给你自己想或者是$py$一下代码

 

 然后处理出一个$l$数组与一个$r$数组,其中

$l[i]$:第i个气候区最左边的点的下标

$r[i]$:第i个气候区最右边的点的下标

那么状转为$$dp[i][0]=Min(dp[i-1][0]+dis(l[i-1],r[i]),dp[i-1][1]+dis(r[i-1],r[i]))+dis(r[i],l[i])$$

$$dp[i][1]=Min(dp[i-1][0]+dis(l[i-1],l[i]),dp[i-1][1]+dis(r[i-1],l[i]))+dis(l[i],r[i])$$

状转都出来了,为什么不上代码?

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define cg (c=getchar())
inline int qread(){
    int x,f=1;char c;
    while(cg<'0'||'9'<c)if(c=='-')f=-1;
    for(x=(c^48);'0'<=cg&&c<='9';x=(x<<1)+(x<<3)+(c^48));
    return x*f;
}
#undef cg
template<class T>inline T Max(const T x,const T y){return x>y?x:y;}
template<class T>inline T Min(const T x,const T y){return x<y?x:y;}
template<class T>inline T fab(const T x){return x>0?x:-x;}
const int MAXN=3e5;
struct node{
    int x,y,c;
    node(){x=y=c=0;}
    node(const int X,const int Y):x(X),y(Y),c(Max(X,Y)){}
    node(const int X,const int Y,const int C):x(X),y(Y),c(C){}
    bool operator<(const node& a){
        if(c!=a.c)return c<a.c;
        if(x!=a.x)return x<a.x;
        return y<a.y;
    }
}dat[MAXN+5];
inline int dis(const int i,const int j){return fab(dat[i].x-dat[j].x)+fab(dat[i].y-dat[j].y);}
int hasind;
int dp[MAXN+5][2];
int l[MAXN+5],r[MAXN+5];
signed main(){
    int N=qread();
    for(int i=1,a,b;i<=N;++i){a=qread(),b=qread();dat[i]=node(a,b);}
    sort(dat+1,dat+N+1);
    l[hasind]=0;
    for(int i=1,pre=0;i<=N;++i){
        if(dat[i].c^pre){
            r[hasind]=i-1;
            pre=dat[i].c;
            l[++hasind]=i;
        }
        dat[i].c=hasind;
    }
    r[hasind]=N;
    for(int i=1;i<=hasind;++i){
        dp[i][0]=Min(dp[i-1][0]+dis(l[i-1],r[i]),dp[i-1][1]+dis(r[i-1],r[i]))+dis(r[i],l[i]);
        dp[i][1]=Min(dp[i-1][0]+dis(l[i-1],l[i]),dp[i-1][1]+dis(r[i-1],l[i]))+dis(l[i],r[i]);
    }
    printf("%lld\n",Min(dp[hasind][0]+dis(l[hasind],0),dp[hasind][1]+dis(r[hasind],0)));
    return 0;
}

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!