一开始直接spfa T了。。
再看这个图发现有猫腻 2e6个点分列两侧 且只与东西两点还有河对岸的点有边 那起点 p 到任意一个点 i 的最短路径(默认 i 在p东边)只有两种情况
1 从p一直向东 途中可能纵向过几次河 但横向方向不变
2 从p先向西再向东 通过迂回路线来回避一些耗时高的路段 且最多迂回一次 多了必定走重复路线
为了保证满足第二种情况 首先从p向西一路“dp”到最西边 再从最西边一路“dp”回p(这一段路也可能会有迂回 所以要反向一次)这样做主要是为了保证 p 河对岸的那个点有最优解 然后再从p一路”dp“到最东边 再从最东边回来(还是为了迂回)此时每个点都已得到最优解
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[1000010][2];
int dn[1000010],line[1000010],ds[1000010];
int n;
int main()
{
int i,ta,a,tb,b,t;
while(scanf("%d",&n)!=EOF)
{
if(n==0) break;
scanf("%d%d%d%d",&ta,&a,&tb,&b);
if(a>b)
{
t=ta,ta=tb,tb=t;
t=a,a=b,b=t;
}
for(i=1;i<=n;i++)
{
scanf("%d",&dn[i]);
}
for(i=0;i<=n;i++)
{
scanf("%d",&line[i]);
}
for(i=1;i<=n;i++)
{
scanf("%d",&ds[i]);
}
memset(dp,0x3f,sizeof(dp));
if(a==0)
{
dp[a][ta]=0,dp[a][(ta+1)%2]=line[a];
for(i=1;i<=n;i++)
{
dp[i][0]=dp[i-1][0]+dn[i],dp[i][1]=dp[i-1][1]+ds[i];
dp[i][0]=min(dp[i][0],dp[i][1]+line[i]);
dp[i][1]=min(dp[i][1],dp[i][0]+line[i]);
}
for(i=n-1;i>=0;i--)
{
dp[i][0]=min(dp[i][0],min(dp[i+1][0]+dn[i+1],dp[i][1]+line[i]));
dp[i][1]=min(dp[i][1],min(dp[i+1][1]+ds[i+1],dp[i][0]+line[i]));
}
printf("%d\n",dp[b][tb]);
}
else
{
dp[a][ta]=0,dp[a][(ta+1)%2]=line[a];
for(i=a-1;i>=0;i--)
{
dp[i][0]=dp[i+1][0]+dn[i+1],dp[i][1]=dp[i+1][1]+ds[i+1];
dp[i][0]=min(dp[i][0],dp[i][1]+line[i]);
dp[i][1]=min(dp[i][1],dp[i][0]+line[i]);
}
for(i=1;i<=a;i++)
{
dp[i][0]=min(dp[i][0],min(dp[i-1][0]+dn[i],dp[i][1]+line[i]));
dp[i][1]=min(dp[i][1],min(dp[i-1][1]+ds[i],dp[i][0]+line[i]));
}
for(i=a+1;i<=n;i++)
{
dp[i][0]=dp[i-1][0]+dn[i],dp[i][1]=dp[i-1][1]+ds[i];
dp[i][0]=min(dp[i][0],dp[i][1]+line[i]);
dp[i][1]=min(dp[i][1],dp[i][0]+line[i]);
}
for(i=n-1;i>=a;i--)
{
dp[i][0]=min(dp[i][0],min(dp[i+1][0]+dn[i+1],dp[i][1]+line[i]));
dp[i][1]=min(dp[i][1],min(dp[i+1][1]+ds[i+1],dp[i][0]+line[i]));
}
printf("%d\n",dp[b][tb]);
}
}
return 0;
}