题意:n个点的完全有向图.边权为:|xi-xj|+ci+bj (j<i) |xi-xj|+di+aj (j>i)
求从s出发,经过每个点正好一次达到t的最短路径? n<=5000
按上面直接连边后,变成求最短哈密顿路???
边的值不是任意的,和两点的距离以及其对应a,b,c,d有关,把边的累加和拆成每个单点贡献后的累加和.
一个结点可以有4个状态:路径中pre为左/右,nxt为左/右.知道该点状态就能知道在路径中的贡献.
设f[i][j][k] 状态:前i个点,j个入边待定,k个出边待定.(i,j)可以确定k,记忆化时可以优化掉一维.合法转移即可.
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=5e3+5;
const ll inf=2e16;
int n,s,t,x[N],a[N],b[N],c[N],d[N];
ll dp[N][N];
ll solve(int i,int j,int k)
{
if(i==n)
{
if(j==0&&k==0)
return dp[i][j]=0;
return inf;
}
if(j==0&&k==0&&i)
return inf;
if(dp[i][j]!=-1)
return dp[i][j];
ll &res=dp[i][j];
res=inf;
if(i==s)
{
if(j) res=min(res,solve(i+1,j-1,k)+x[i]+c[i]);//nxt is some left.
res=min(res,solve(i+1,j,k+1)-x[i]+d[i]);//nxt is some right
return res;
}
if(i==t)
{
if(k) res=min(res,solve(i+1,j,k-1)+x[i]+a[i]);
res=min(res,solve(i+1,j+1,k)-x[i]+b[i]);//p,r
return res;
}
res=min(res,solve(i+1,j+1,k+1)-2*x[i]+b[i]+d[i]);
if(k&&j)
res=min(res,solve(i+1,j-1,k-1)+2*x[i]+a[i]+c[i]);
if(k)
res=min(res,solve(i+1,j,k)+d[i]-x[i]+x[i]+a[i]);
if(j)
res=min(res,solve(i+1,j,k)+c[i]+b[i]);
return res;
}
int main()
{
while(cin>>n>>s>>t)
{
memset(dp,-1,sizeof(dp));
s--,t--;
for(int i=0;i<n;i++)
scanf("%d",&x[i]);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=0;i<n;i++)
scanf("%d",&b[i]);
for(int i=0;i<n;i++)
scanf("%d",&c[i]);
for(int i=0;i<n;i++)
scanf("%d",&d[i]);
printf("%I64d\n",solve(0,0,0));
}
return 0;
}