【tyvj1061】Mobile Service(dp)

题目:我是超链接

题解:

可以发现这是一道dp题目,设计状态f[i][j][k][l]表示第i请求时,服务员分别位于j,k,l位置,发现转移也很简单,可以从j||k||l转移到b[i],而且这一请求的转移只会是上一个请求,所以可以用滚动数组优化,但我们发现这样超低的效率是O(nl^3),如何优化?

因为这一时刻一结束,一定有一个服务员位于b[i],所以上一时刻的服务员位置为j,k,b[i-1]这样枚举可以少上一维,那我们设计状态f[i][j][k]表示第i个请求时,服务员位于j,k,消去的那一维在b[i-1],转移很好写出

其实还有一个优化,我们发现f[2][1][3]和f[2][3][1]表示一个意思,可以省去一些,使光存储j<k的状态

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#define INF 1e9
using namespace std;
int a[205][205],b[1005],f[2][205][205];
int main()
{
	int l,n,i,j,k;
	scanf("%d%d",&l,&n);
	for (i=1;i<=l;i++) 
	  for (j=1;j<=l;j++) scanf("%d",&a[i][j]);
	for (i=1;i<=n;i++) scanf("%d",&b[i]);
	memset(f,0x7f,sizeof(f));
	if (b[1]!=2 && b[1]!=3)	f[1][2][3]=a[1][b[1]];
	if (b[1]!=1 && b[1]!=3)	f[1][1][3]=a[2][b[1]];
	if (b[1]!=1 && b[1]!=2)	f[1][1][2]=a[3][b[1]];
	for (i=2;i<=n;i++)//坐标分别为j,k,b[i-1],jk代表不在b[i-1]的那两个人的位置 
	{
		memset(f[i%2],0x7f,sizeof(f[i%2]));
		for (j=1;j<=l;j++)
	    for (k=j+1;k<=l;k++)
	    {
	    	if (j!=b[i] && k!=b[i])	f[i%2][j][k]=min(f[i%2][j][k],f[(i-1)%2][j][k]+a[b[i-1]][b[i]]);
	    	
	    	if (j!=b[i] && b[i-1]!=b[i])
	    	{
	    		if (b[i-1]>j) f[i%2][j][b[i-1]]=min(f[i%2][j][b[i-1]],f[(i-1)%2][j][k]+a[k][b[i]]);
	    	    else f[i%2][b[i-1]][j]=min(f[i%2][b[i-1]][j],f[(i-1)%2][j][k]+a[k][b[i]]);
			}
			
			if (k!=b[i] && b[i-1]!=b[i])
			{
				if (b[i-1]>k) f[i%2][k][b[i-1]]=min(f[i%2][k][b[i-1]],f[(i-1)%2][j][k]+a[j][b[i]]);
	    	    else f[i%2][b[i-1]][k]=min(f[i%2][b[i-1]][k],f[(i-1)%2][j][k]+a[j][b[i]]);
			} 	
		}
	}
	int ans=INF;
	for (i=1;i<=l;i++)
	  for (j=i+1;j<=l;j++)
	    if (i!=b[n] && j!=b[n])
	    ans=min(ans,f[n%2][i][j]);
	printf("%d",ans);
}

总结:两个优化

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值