P3842 [TJOI2007]线段

每行一个线段,必须要走完,显然可以发现从左往右走完或者从右往左走完是比较优的。从中间往下走浪费步数??(好像可以,但是我理解不来,也找不到有人这样写)
那么是该从左往右还是从右往左呢。我们需要枚举了。这个状态又有最优子结构,这时候需要优雅的暴力--DP。

\(f[i][0]\)表示走完第i行的线段,并且在该线段左边时的最小步数
\(f[i][1]\)表示走完第i行的线段,并且在该线段右边时的最小步数

\(f[i][0/1]\)可以从\(f[i-1][1/0]\)得出,分类讨论即可。
关于为什么这样走最优,可以画图自己平移下


#include<bits/stdc++.h>
#define rep(i,j,k) for(register int i(j);i<=k;++i)
#define drp(i,j,k) for(register int i(j);i>=k;--i)
using namespace std;
typedef long long lxl;
template<typename T> 
inline T  max(T &a, T &b) {
	return a > b ? a : b;
}
template<typename T> 
inline T  min(T &a, T &b) {
	return a < b ? a : b;
}

inline char gt() {
	static char buf[1 << 21], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
template <typename T>
inline void  read(T &x) {
	register char ch = gt();
	x = 0;
	int w(0);
	while(!(ch >= '0' && ch <= '9'))w |= ch == '-', ch = gt();
	while(ch >= '0' && ch <= '9')x = x * 10 + (ch & 15), ch = gt();
	w ? x = ~(x - 1) : x;
}
template <typename T>
inline void out(T x) {
	if(x < 0) x = -x, putchar('-');
	char ch[20];
	int num(0);
	while(x || !num) ch[++num] = x % 10 + '0', x /= 10;
	while(num) putchar(ch[num--]);
	putchar('\n');
}
const int N=2e4+79;
int L[N],R[N]; 
int f[N][2];
int n;

inline int dis(int a,int b){
	return abs(a-b);
}

int main() {  
   read(n);
   rep(i,1,n) {
   	read(L[i]);read(R[i]);
   }
   memset(f,0x3f,sizeof f);
   f[1][1]=R[1]-1;
   f[0][1]=R[1]-1+(R[1]-L[1]);
   
   rep(i,2,n){
   	f[i][1]=min(f[i-1][1]+dis(R[i-1],L[i])+dis(L[i],R[i]),f[i-1][0]+dis(L[i-1],L[i])+dis(L[i],R[i]))+1;
   	f[i][0]=min(f[i-1][1]+dis(R[i-1],R[i])+dis(R[i],L[i]),f[i-1][0]+dis(L[i-1],R[i])+dis(L[i],R[i]))+1;
   }
   out(min(f[n][1]+dis(R[n],n),f[n][0]+dis(L[n],n)));
	return 0;
}

当然这题也可以跑最短路。。网格图。要学会一题多解(强行增加时间复杂度,但是可以增强编程能力)
增强建图能力(乱搞)
去luogu看吧,懒得写了

上一篇:【学术】对于代码常系数影响因素的考察——以快读为例


下一篇:inline function--内联函数