感觉自己dp这方面还需要加强啊。
显然一个合法的方案已定包含一条0-N+1的上行链(可以拼接得到),剩下的是一些环。
令dp[i][j]表示盖了前i个邮戳,并且从下行站走到上行站的次数-从上行站走到下行站的次数=j时,不计0-i的上行链的时间时的最小耗费。
j可能比较费解。形象一点,由于剩下的是一些环,那么环一定是i的上行站->i的下行站->j的下行站->i的下行站->i的上行站。环一定是有些整体在i的前面,或者整体在i的后面,或者跨过i,j就是跨过i的环的数量。
然后枚举第i个站点的走法:(上行站或下行站)->邮戳台->(下行站或下行站)共四种;再加上直接从上行站->下行站(包括反向)的转移。因此一共是六种。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define N 3005
using namespace std;
int n,m; long long f[N][N];
void dn(int &x,int y){ if (y<x) x=y; }
int main(){
scanf("%d%d",&n,&m); int i,j,x,y,u,v;
memset(f,0x3f,sizeof(f));
f[0][0]=0;
for (i=1; i<=n; i++){
scanf("%d%d%d%d",&x,&y,&u,&v);
for (j=0; j<=n; j++) f[i-1][j]+=j*m<<1;
for (j=0; j<=n; j++){
if (j) f[i][j]=min(min(f[i-1][j-1],f[i][j-1])+y+u,f[i-1][j]+u+v);
if (j<n) f[i][j]=min(f[i][j],f[i-1][j+1]+x+v);
f[i][j]=min(f[i][j],f[i-1][j]+x+y);
}
for (j=n-1; j>=0; j--) f[i][j]=min(f[i][j],f[i][j+1]+x+v);
}
printf("%lld\n",f[n][0]+(n+1)*m);
return 0;
}
by lych
2016.3.26