农夫打狼

题目描述

小明是某RTS游戏的狂热爱好者,但是他从来不好好打游戏,经常搞出一些令人窒息的操作。一次,他竟然将自己的一个农夫派出去打野狼。

农夫初始时站在地图坐标(0,0)的位置,地图的出口的坐标为(n,n),地图上共有m只野狼,每只野狼有一个坐标(xi,yi),数据保证不会有两个野狼在相同的位置。农夫只有消灭地图上所有的野狼才能完成任务。

整个地图按y轴一共分为n层,当且仅当农夫清掉了本层的所有怪物之后才能到下一层,比如说,如果农夫当前的位置是(x,3),那么他必须将y坐标等于3的所有野狼消灭,才允许走到(x,4)。如果本层没有怪物,农夫能够直接到下一层。

由于小明使用的种族是Magyar,这个种族骁勇善战,农夫只需一击就能将野狼打死。因而,每到一个位置,如果这个位置有野狼,他可以直接将怪物秒掉(不需要任何操作)。

现在给出m个野狼的坐标,问农夫最少需要走多少步才能完成任务。农夫向上下左右移动一格算一步。

输入
第一行两个数n,m(n,m<=100,000)。 接下来m行,每行两个数,代表第i只野狼的坐标。

输出
第一行两个数n,m(n,m<=100,000)。 接下来m行,每行两个数,代表第i只野狼的坐标。

样例输入
4 5
1 1
2 1
1 2
3 2
3 3

样例输出
10

注意:
此题数据规模极大,后台25组数据,都是上万个坐标,而且狼的坐标(x,y)存在y>n的情况,还是我找bug的时候加了一行判断看看会不会tile,果然tle了…
在这里插入图片描述
正确代码:

25组测试点全过

#include<bits/stdc++.h>
using namespace std;
const int MAX=2e6+10;
long long dp[MAX][2];//dp[i][0]表示left,dp[i][1]表示right
int data[MAX][2];//data[i][0]表示left,data[i][1]表示right
int n,m;
int Max;
inline long long min(long long a,long long b){
    return a>b?b:a;
}
inline long long max(long long a,long long b){
    return a>b?a:b;
}
inline int Calc(int a,int b){
    return a-b>=0?a-b:0;
}
void init(){
    memset(data,-1,sizeof(data));
    cin>>n>>m;
    int x,y;
    data[0][0]=0;
    data[0][1]=0;
    Max=0;
    for(int i=0;i<m;i++){
        scanf("%d %d",&x,&y);
        Max=Max>y?Max:y;
        if(data[y][0]==-1){
            data[y][0]=x;
            data[y][1]=x;
        }else{
            data[y][0]=min(data[y][0],x);
            data[y][1]=max(data[y][1],x);
        }
    }
}
void solve(){
    int L=data[0][0],R=data[0][1];
    dp[0][0]=2*(R-L);
    dp[0][1]=R-L;
    for(int i=1;i<=Max;i++){
        int LL=data[i][0];
        int RR=data[i][1];
        if(LL==-1){
            dp[i][0]=dp[i-1][0]+1;
            dp[i][1]=dp[i-1][1]+1;
        }else{
            //dp[i][0]=min(L->LL,R->LL);
            dp[i][0]=min(2*Calc(RR,L)+L-LL+dp[i-1][0]+1,2*Calc(RR,R)+R-LL+dp[i-1][1]+1);
            //dp[i][1]=min(L->RR,R->RR);
            dp[i][1]=min(2*Calc(L,LL)+RR-L+dp[i-1][0]+1,2*Calc(R,LL)+RR-R+dp[i-1][1]+1);
            //cout<<"i="<<i<<":L:="<<L<<" R:"<<R<<" LL:"<<LL<<" RR="<<RR<<" dp[0]="<<dp[i][0]<<" dp[1]="<<dp[i][1]<<endl;
            L=LL;
            R=RR;
        }
    }
    cout<<min(dp[Max][0]+abs(Max-n)+abs(L-n),dp[Max][1]+abs(Max-n)+abs(R-n))<<endl;
}
int main(){
    init();
    solve();
    return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值