[ 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;
}