[POJ 3926][Vjudge 19611] Parade [动态规划+单调队列]

26 篇文章 0 订阅
20 篇文章 0 订阅

有一个人要从最下边走到最上边,只能往上走不能往下走,在同一层只能往左或往右,不能来回走,每层上每个横着的边都有一个花费和一个收益,要求在一层上的花费不能超过k,可以不再这一层走直接走向下一层,求最大收益。

直接DP,状态为dp[i][j]表示从最下边走到第i层的第j列,且已经在第i层走过了,即不会再在第i层上走了的最大收益。

这样是n*m的状态,每个状态是m的转移,可以用单调队列优化掉转移的复杂度,变成均摊O(1)的转移。

#include <cstdio>
#include <cstring>

struct QueNode {
	int v,x;
	void clear(int vv,int xx) {
		v=vv;x=xx;
	}
};
int n,m,k;
int a[112][10011];
int b[111][10011];
int dp[111][10011];
QueNode que[10011];
int p,q;
int sum,x;

inline int in() {
	char c=getchar();
	while ((c<'0'||c>'9')&&c!='-') c=getchar();
	bool flag=false;
	if (c=='-') {
		flag=true;
		c=getchar();
	}
	int ans=0;
	while (c>='0'&&c<='9') {
		ans=ans*10+c-'0';
		c=getchar();
	}
	//printf("%d\n",ans);
	if (flag) return -ans;
	return ans;
}

int main() {
	int i,j;
	while (scanf("%d%d%d",&n,&m,&k),n!=0) {
		for (i=0;i<=n;i++)
			for (j=0;j<m;j++)
				a[i][j]=in();
		for (i=0;i<=n;i++)
			for (j=0;j<m;j++)
				b[i][j]=in();
		for (j=0;j<=m;j++) dp[n+1][j]=0;
		for (i=n;i>=0;i--) {
			x=sum=p=q=0;
			dp[i][0]=dp[i+1][0];
			que[q++].clear(dp[i+1][0],0);
			for (j=1;j<=m;j++) {
				x+=b[i][j-1];
				sum+=a[i][j-1];
				int tmp=dp[i+1][j]-sum;
				while (p<q&&que[q-1].v<=tmp) q--;
				while (p<q&&x-que[p].x>k) p++;
				que[q++].clear(tmp,x);
				dp[i][j]=que[p].v+sum;
			}
			x=sum=p=q=0;
			que[q++].clear(dp[i+1][m],0);
			for (j=m-1;j>=0;j--) {
				x+=b[i][j];
				sum+=a[i][j];
				int tmp=dp[i+1][j]-sum;
				while (p<q&&que[q-1].v<=tmp) q--;
				while (p<q&&x-que[p].x>k) p++;
				que[q++].clear(tmp,x);
				if (dp[i][j]<que[p].v+sum)
					dp[i][j]=que[p].v+sum;
			}
		}
		int ans=0;
		for (j=0;j<=m;j++)
			if (dp[0][j]>ans) ans=dp[0][j];
		/*
		for (i=0;i<=n;i++) {
			for (j=0;j<=m;j++)
				printf("%d ",dp[i][j]);
			printf("\n");
		}
		*/
		printf("%d\n",ans);
	}
	return 0;
}



  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值