DP分类讨论,状态定义

FJOI2018邮递员问题-冯金伟博客园
FJOI2018邮递员问题-冯金伟博客园

街道可以乱窜,起点终点确定,求遍历所有点的最短路径

感觉好难,只会10分

网络流暴力30分

哎~

做题要多思考,不要看题解,也不要看了题解就完了,还有很多做法

SOL:

FJOI2018邮递员问题-冯金伟博客园

参考自yyb

#include<bits/stdc++.h>
using namespace std;
const int N=1e4+4;
int n[2],ty[2],pos[2];
double h,tx[2],a[2][N],f[N][2];
inline double dis(int i,int j){
	static double d;
	d=fabs(a[0][i]-a[1][j]);
	return sqrt(d*d+h*h);
} 
inline double toend(int i,int j){
	static double d;
	d=fabs(a[i][j]-tx[1]);
	return i==ty[1]?d:sqrt(h*h+d*d);
}
inline double solve(){
	double ret=1e18;
	sort(a[0],a[0]+n[0]+1);
	sort(a[1],a[1]+n[1]+1);
	for(int i=n[0];i;--i){//0->(i,j+1) 1->(i+1,j)
		if(i==n[0])for(int j=n[1];j;--j){
			f[j][0]=(j==n[1]?toend(0,n[0]):min(f[j+1][1]+dis(i,j+1),dis(i,n[1])+a[1][n[1]]-a[1][j+1]+toend(1,j+1)));
			f[j][1]=(j==n[1]?toend(1,n[1]):f[j+1][1]+a[1][j+1]-a[1][j]);
		}//
		else for(int j=n[1];j;--j)
			if(j==n[1]){
				f[j][1]=min(f[j][0]+dis(i+1,j),dis(n[0],n[1])+a[0][n[0]]-a[0][i+1]+toend(0,i+1));
				f[j][0]+=a[0][i+1]-a[0][i];
			}
			else{
				f[j][1]=min(f[j][0]+dis(i+1,j),f[j+1][1]+a[1][j+1]-a[1][j]);
				f[j][0]=min(f[j+1][1]+dis(i,j+1),f[j][0]+a[0][i+1]-a[0][i]);
			}
		ret=min(ret,a[0][i]-a[0][1]+tx[0]-a[0][1]+dis(i,1)+f[1][1]);
		ret=min(ret,fabs(a[0][i]-tx[0])+a[0][i]-a[0][1]+dis(1,1)+f[1][1]);
		if(a[0][i]<=tx[0]){
			ret=min(ret,tx[0]-a[0][1]+dis(1,1)+f[1][1]);
			break;
		}
	}
	return ret; 
}
int main(){
	scanf("%d%d%d%d%d%d%lf",&n[0],&n[1],&ty[0],&pos[0],&ty[1],&pos[1],&h);
	int r=0;
	if(ty[0]){r=1;swap(n[0],n[1]);ty[0]^=1;ty[1]^=1;}
	for(int t=0;t^2;++t)
		for(int i=1;i<=n[t^r];++i)
			scanf("%lf",&a[t^r][i]);
	tx[0]=a[ty[0]][pos[0]];
	tx[1]=a[ty[1]][pos[1]];
	double ans=solve();
	for(int t=0;t^2;++t)
		for(int i=1;i<=n[t];i++)
			a[t][i]=20000-a[t][i];
	tx[0]=20000-tx[0];
	tx[1]=20000-tx[1];
	ans=min(ans,solve());
	printf("%.2lf",ans);
	return (0-0);
}