poj 2609 动态规划

17 篇文章 0 订阅

DP,注意单组输入,题目的进程无后效性,适合DP,

由于当时没有估计出车子数量,用了滚动数组。

现在来谈下DP状态的表示,

比较容易想到的是DP【i】【j】【k】(现在的车子编号,队列1长度,队列2长度)

明显MLE,其实我们只需要有前两维即可,因为最后一维可以从前面两维推知:k=sum【i】-j;

问题转为存在性问题了,dp【i】【j】=dp【i-1】【j】|dp【i-1】【j-len【i】】(分别为放在队列1,放在队列2)

注意细节处理

详情见代码:

#include<stdio.h>
#include<string.h>
const int maxn=10007;
bool dp[2][maxn];//表示第i辆车时,第一个队列装了J的容量
int  pre[501][maxn];
int sum[501];
int q[501];
void output(int ,int );
int main()
{
	int max,i,j,a,ans,nn,c,T;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d",&max);
		nn=1,ans=0,c=0;
		max*=100;
		memset(sum,0,sizeof(sum));
		while(scanf("%d",&a)&&a)
			q[nn++]=a;
		sum[1]=q[1];
		for(i=2;i<nn;i++)
			sum[i]+=sum[i-1]+q[i];
		memset(dp,false,sizeof(dp));
		memset(pre,-1,sizeof(pre));
		dp[0][0]=true;
		for(i=1;i<nn;i++)
		{
			memset(dp[i&1],false,sizeof(dp[i&1]));
			for(j=max;j>=0;j--)//第一个队列的长度
			{
				if(sum[i-1]-j>max)//第二个队列爆了
					break;
				if(sum[i]-j<=max)//第二个队列还能装得下
				{
					if(j-q[i]>=0)
						dp[i&1][j]=dp[(i-1)&1][j]|dp[(i-1)&1][j-q[i]];
					else dp[i&1][j]=dp[(i-1)&1][j];
					if(dp[(i-1)&1][j]) 
						pre[i][j]=0;//表示装在第二个队列
					else if(j-q[i]>=0&&dp[(i-1)&1][j-q[i]]) 
						pre[i][j]=1;
				}
				else if(j-q[i]>=0)
				{
					dp[i&1][j]=dp[(i-1)&1][j-q[i]];
					pre[i][j]=1;
				}
				if(dp[i&1][j])
				{
					c=j;
					ans=i;
				}
			}
			if(ans!=i) //如果这一个车子无法被装下,break
				break;
		}
		printf("%d\n",ans);
		if(ans) 
			output(ans,c);
	}
	return 0;
}
void output(int x,int y)
{
	if(x<=0) return ;
	if(pre[x][y]==1)
	{
		output(x-1,y-q[x]);
		printf("port\n");
	}
	else if(pre[x][y]==0)
	{
		output(x-1,y);
		printf("starboard\n");
	}
	else if(pre[x][y]==-1)
	{
		while(1) puts("S");
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值