Codeforces 705D Ant Man DP(贡献)

来源:互联网 发布:php好学还是java好学 编辑:程序博客网 时间:2024/05/17 07:11

题意: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 rightreturn 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,rreturn 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;}