[ TJOI 2007 ] 线段

(\)

(Description)


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

  • (Nle 2 imes10^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
",ans);
  return 0;
}
原文地址:https://www.cnblogs.com/SGCollin/p/9780810.html