【bzoj4244】邮戳拉力赛 动态规划

       感觉自己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

你可能感兴趣的:(动态规划)