tyvj-1061 Mobile Service 基础dp

题意:一个公司有三个移动服务员。如果某个地方有一个请求,某个员工必须赶到那个地方去(那个地方没有其他员工),某一时刻只有一个员工能移动。被请求后,他才能移动,不允许在同样的位置出现两个员工。从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;
}

猜你喜欢

转载自blog.csdn.net/zhengyuan233/article/details/79666144