题意:一个公司有三个移动服务员。如果某个地方有一个请求,某个员工必须赶到那个地方去(那个地方没有其他员工),某一时刻只有一个员工能移动。被请求后,他才能移动,不允许在同样的位置出现两个员工。从p到q移动一个员工,需要花费c(p,q),c(p,p)=0。公司必须满足所有的请求。目标是最小化公司花费。一开始三个服务员分别在位置1,2,3。
输入格式
第一行有两个整数L,N(3<=L<=200, 1<=N<=1000)。L是位置数;N是请求数。每个位置从1到L编号。下L行每行包含L个非负整数。第i+1行的第j个数表示c(i,j) ,并且它小于2000。最后一行包含N个数,是请求列表。
输出格式
一个数M,表示最小服务花费。
输入样例 #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
思路:一开始想的是开一个三维数组dp[i][j][k] 表示当执行第i个请求时 第j个人位于第k个位置所形成的最小花费
写了个假方程 dp[i][j][que[i]] = min( dp[i][j][que[i]] ,dp[i-1][j][k]+cost[k][que[i]] );
但这个状态转移方程很明显有一个致命的错误 就是无法保证某一时刻只有一个员工可以移动
之后又加了一维发现还是有bug 于是变换思路
dp[i][j][k][z] 表示第i个请求时 三个人的位置分别为j k z
这样dp[i+1][que[i+1]][k][z] = min(dp[i+1][que[i+1]][k][z] , dp[i][j][k][z] + cost[j][que[i+1]] );
以此类推出三个状态转移方程 分别表示第1、2、3个服务员从j、k、z前往que[i+1]所需要的最小花费
但是这样空间复杂度大大超出了我们的承受范围 1000*200*200*200是不行的
通过观察可得 每一时刻必定有一个服务员在que[i]这个位置上 也就是说其中一个服务员的位置是不需要储存的 一定是que[i]
这样que[0] = 3 dp[0][1][2] = 0 que[i+1][j][k] = min(que[i+1][j][k],que[i][j][k] + cost[que[i]][que[i+1]);
以此类推三个状态转移方程 分别表示三种情况 从j出发到que[i+1] 从k出发到que[i+1] 从que[i]出发到que[i+1]
所以就可以优化空间复杂度 变成1000*200*200
然而这样也超出了内存限制 继续思考可知 dp方程其实只跟前一项有关 即每次i+1都是从i推出的 而与0~i无关
所以我们可以利用滚动数组 只储存前后两个相邻时刻的关系 忽略之前所有状态 这样空间复杂度就变成了2*200*200
我们就可以顺利完成这道题了
AC代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
int dp[1100][202][202];
#define inf 0x3f3f3f3f
int cost[220][220];
int que[1100];
int main()
{
memset(dp,inf,sizeof(dp));
int n,q;
cin >> n >> q;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
cin >> cost[i][j];
}
}
for(int i = 1; i <= q; i++)
{
cin >> que[i];
}
dp[0][1][2] = 0;
que[0] = 3;
for(int i = 0; i < q; i++)
{
for(int j = 1; j <= n; j++)
{
for(int k = 1; k <= n; k++)
{
if(i%2==0)
{
dp[1][que[i]][k] = min(dp[1][que[i]][k],dp[0][j][k]+cost[j][que[i+1]]);
dp[1][j][que[i]] = min(dp[1][j][que[i]],dp[0][j][k]+cost[k][que[i+1]]);
dp[1][j][k] = min(dp[1][j][k],dp[0][j][k]+cost[que[i]][que[i+1]]);
dp[0][que[i]][k] = inf;
dp[0][j][que[i]] = inf;
dp[0][j][k] = inf;
}
else
{
dp[0][que[i]][k] = min(dp[0][que[i]][k],dp[1][j][k]+cost[j][que[i+1]]);
dp[0][j][que[i]] = min(dp[0][j][que[i]],dp[1][j][k]+cost[k][que[i+1]]);
dp[0][j][k] = min(dp[0][j][k],dp[1][j][k]+cost[que[i]][que[i+1]]);
dp[1][que[i]][k] = inf;
dp[1][j][que[i]] = inf;
dp[1][j][k] = inf;
}
}
}
}
int ans = inf;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= n; j++)
{
ans = min(ans,dp[q%2][i][j]);
}
}
cout<<ans<<endl;
}