【8.24模拟赛T3.1327】Mobile Service【DP】

在这里插入图片描述
在这里插入图片描述
哦对,在gmoj上是没有多组数据的。

题目链接:https://www.luogu.com.cn/problem/SP703https://gmoj.net/senior/#main/show/1327

分析

我一开始居然想到一个一个贪心去了

四维DP比较好想:
f [ i ] [ x ] [ y ] [ z ] f[i][x][y][z] f[i][x][y][z]表示当前第i个任务,第一个员工在 x x x,第二个在 y y y,第三个在 z z z

但是时间空间都不行,怎么办?

然后可以发现这个题的一个性质,每次做任务后一定有一个员工停在p[i]处,所以就可以优化

f [ i ] [ x ] [ y ] f[i][x][y] f[i][x][y]表示完成 i i i个目标,两个人停在 x , y x,y x,y位置,另一个人停在 p [ i ] p[i] p[i]处,则有转移:
f [ i + 1 ] [ j ] [ k ] = m i n ( f [ i + 1 ] [ j ] [ k ] , f [ i ] [ j ] [ k ] + a [ b [ i ] ] [ b [ i + 1 ] ] ) ; f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]+a[b[i]][b[i+1]]); f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]+a[b[i]][b[i+1]]);

f [ i + 1 ] [ b [ i ] ] [ k ] = m i n ( f [ i + 1 ] [ b [ i ] ] [ k ] , f [ i ] [ j ] [ k ] + a [ j ] [ b [ i + 1 ] ] ) ; f[i+1][b[i]][k]=min(f[i+1][b[i]][k],f[i][j][k]+a[j][b[i+1]]); f[i+1][b[i]][k]=min(f[i+1][b[i]][k],f[i][j][k]+a[j][b[i+1]]);

f [ i + 1 ] [ j ] [ b [ i ] ] = m i n ( f [ i + 1 ] [ j ] [ b [ i ] ] , f [ i ] [ j ] [ k ] + a [ k ] [ b [ i + 1 ] ] ) ; f[i+1][j][b[i]]=min(f[i+1][j][b[i]],f[i][j][k]+a[k][b[i+1]]); f[i+1][j][b[i]]=min(f[i+1][j][b[i]],f[i][j][k]+a[k][b[i+1]]);

比赛的时候很自信交了这个代码,结果。。。MLE0分!与AK擦肩而过
一看数据范围65536KB,1000200200直接炸掉,于是要滚动数组。

看到转移只跟当前和上一个有关系,滚掉第一维。用奇偶性的原理滚动,具体见注释。

上代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

int n,q;
int a[201][201],b[2001],f[2][201][201];//滚动原理:奇偶性 

int main()
{
	cin>>n>>q;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			scanf("%d",&a[i][j]);
		}
	}
	for(int i=1;i<=q;i++) cin>>b[i];
	memset(f,0x3f3f3f3f,sizeof(f));
	f[0][1][2]=0;
	b[0]=3;
	for(int i=0;i<q;i++)//这里是从i转到i+1,也可以从i-1转到i,方法相同 
	{
		memset(f[i&1^1],0x3f3f3f3f,sizeof(f[i&1^1]));//清空i+1那一维 
		for(int j=1;j<=n;j++)
		{
			for(int k=1;k<=n;k++)
			{
				/*转移*/ 
				if(b[i+1]!=j&&b[i+1]!=k) 
				  f[i&1^1][j][k]=min(f[i&1^1][j][k],f[i&1][j][k]+a[b[i]][b[i+1]]);
				  
				if(b[i+1]!=k&&b[i+1]!=b[i])
				  f[i&1^1][b[i]][k]=min(f[i&1^1][b[i]][k],f[i&1][j][k]+a[j][b[i+1]]);
				  
				if(b[i+1]!=j&&b[i+1]!=b[i])
				  f[i&1^1][j][b[i]]=min(f[i&1^1][j][b[i]],f[i&1][j][k]+a[k][b[i+1]]);
				  
			}
		}
	}
	int ans=2147483647;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
		    ans=min(ans,f[q&1][i][j]);
		}
	}
	cout<<ans;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值