[ TJOI 2007 ] 线段

\(\\\)

\(Description\)


一个\(N\times N\) 的网格,每行有一段要必走,求从\((1,1)\)\((N,N)\)的最短路长度。

  • \(N\le 2\times10^4\)

\(\\\)

\(Solution\)


论读题的重要性......

注意到除了最后一行,每一行结束处一定在是线段的某一侧,否则其他位置一定会多走一段从端点到这里的距离。

然后就是\(f[i][0/1]\)表示到第\(i\)行线段左端点\(/\)右端点最小步数,转移就是四个了。

转移不用想太多,如果你要到左端点结束,那就得先到右端点,所以答案就是线段长度\(+\)上一状态到右端点距离。

右端点同理。注意答案和转移增量的处理。

\(\\\)

\(Code\)


#include<cmath>
#include<cctype>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define R register
#define gc getchar
#define N 20010
using namespace std;

inline int rd(){
  int x=0; bool f=0; char c=gc();
  while(!isdigit(c)){if(c=='-')f=1;c=gc();}
  while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
  return f?-x:x;
}

int n,ans=0,l[N],r[N],f[N][2];

int main(){
  n=rd();
  memset(f,0x3f,sizeof(f));
  l[1]=rd(); r[1]=rd();
  f[1][0]=r[1]-1+r[1]-l[1];
  f[1][1]=r[1]-1;
  for(R int i=2;i<=n;++i){
    l[i]=rd(); r[i]=rd();
    f[i][0]=min(f[i][0],f[i-1][0]+abs(l[i-1]-r[i])+r[i]-l[i]+1);
    f[i][0]=min(f[i][0],f[i-1][1]+abs(r[i-1]-r[i])+r[i]-l[i]+1);
    f[i][1]=min(f[i][1],f[i-1][0]+abs(l[i-1]-l[i])+r[i]-l[i]+1);
    f[i][1]=min(f[i][1],f[i-1][1]+abs(r[i-1]-l[i])+r[i]-l[i]+1);
  }
  ans=min(f[n][0]+n-l[n],f[n][1]+n-r[n]);
  printf("%d\n",ans);
  return 0;
}
posted @ 2018-10-12 21:26  SGCollin  阅读(156)  评论(0编辑  收藏  举报