题目描述
一个公司有三个移动服务员,最初分别在位置1,2,3处。
如果某个位置(用一个整数表示)有一个请求,那么公司必须指派某名员工赶到那个地方去。某一时刻只有一个员工能移动,且不允许在同样的位置出现两个员工。从 p 到 q 移动一个员工,需要花费 c(p,q)。这个函数不一定对称,但保证 c(p,p)=0。
给出N个请求,请求发生的位置分别为 p_1~p_N。公司必须按顺序依次满足所有请求,目标是最小化公司花费,请你帮忙计算这个最小花费。N≤1000,位置是1~200的整数。
输入格式
第1行:两个空格分隔的整数M, N(3<=M<=200, 1<=N<=1000)。M是位置数;N是请求数。每个位置从1到M编号。
接下来M行:每行包含M个非负整数。第i+1行的第j个数表示c(i,j) ,并且它小于2000。
最后1行包含N个数,是请求列表。一开始三个服务员分别在位置1,2,3。
输出格式
一行:一个整数,表示最小服务花费。
输入输出样例
输入样例1:复制
5 9 0 1 1 1 1 1 0 2 3 2 1 1 0 4 1 2 1 5 0 1 4 2 3 4 0 4 2 4 1 5 4 3 2 1
输出样例1:复制
5
【耗时限制】1000ms 【内存限制】256MB
这一题呢,你需要先理解是什么意思才好写
首先,他是一个线性dp
这个毋庸置疑
那就上思路喽
按顺序完成所有任务,首先考虑按照任务划分阶段:
定义状态:d(i)表示完成前i个任务所需要的最小花费。
状态转移方程:对于第i个任务有3种选择,分别让员工1、2、3来完成。
d(i) = d(i-1)+min(cost(i)) 。
cost(i)表示完成任务i所需的花费,如何计算?
cost(i)的计算需要知道完成任务i-1后3名员工所在的位置,状态参数和状态值中都不包含该信息。
加入位置信息,定义状态:d(i,j,k,l)表示完成任务i后3名员工所在位置分别为j,k,l时的最低花费。
最终答案ans = min(d(n, j, k, l)); 状态维度太多,会超时和超空间!
当完成任务i后,3名员工中必有一人所在位置为p[i],i可以同时代表一个位置,并且3名员工是相同的。
定义状态:d(i, j, k)表示完成任务i后,3名员工所在位置分别为p[i], j, k时的最低花费。
状态转移方程:从拉的角度考虑状态转移方程决策太多,不方便处理,尝试从推的角度进行状态转移,推的话必然是像下一个任务的位置转移,考虑d(i, j, k)可以更新哪些状态。
任务i完成后肯定是要处理问题i+1了,处理问题i+1有3种可选方案(两个员工不能到达同一个位置):
① 从p[i]走到p[i+1]:d(i+1,j,k) = d(i,j,k) + c[p[i]][p[i+1]]; (p[i+1] != j && p[i+1]!=k);
② 从j走到p[i+1]:d(i+1,p[i],k) = d(i,j,k) + c[j][p[i+1]]; (p[i+1] != p[i] && p[i+1]!=k);
③ 从k走到p[i+1]:d(i+1,j,p[i]) = d(i,j,k) + c[k][p[i+1]]; (p[i+1] != p[i] && p[i+1]!=j);
讲完了之后,上代码吧
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=1000+5;
const int INF=0x7fffffff;
int n, m;
int a[210][210],p[N],f[N][210][210];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
scanf("%d",&a[i][j]);
for(int i=1;i<=m;i++)
scanf("%d",&p[i]);
memset(f,0x7f,sizeof(f));
f[0][1][2]=0,p[0]=3;
for(int i=0;i<m;i++)
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++){
int z=p[i];
if(f[i][x][y]==INF) continue;
if (x!=p[i+1]&&y!=p[i+1])
f[i+1][x][y]=min(f[i+1][x][y],f[i][x][y]+a[z][p[i+1]]);
if(z!=p[i+1]&&x!=p[i+1])
f[i+1][x][z]=min(f[i+1][x][z],f[i][x][y]+a[y][p[i+1]]);
if(y!=p[i+1]&&z!=p[i+1])
f[i+1][y][z]=min(f[i+1][y][z],f[i][x][y]+a[x][p[i+1]]);
}
int ans=0x7f7f7f7f;
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
ans=min(ans,f[m][i][j]);
printf("%d\n",ans);
return 0;
}