[CH5102]Mobile Service

1184: 移动服务员


题目描述

一个公司有三个移动服务员。如果某个地方有一个请求,某个员工必须赶到那个地方去(那个地方没有其他员工),某一时刻只有一个员工能移动。被请求后,他才能移动,不允许在同样的位置出现两个员工。

从 p 到 q 移动一个员工,需要花费 c(p,q)。这个函数没有必要对称,但是 c(p,p)=0。公司必须满足所有的请求。目标是最小化公司花费。

输入

第一行有两个整数 L,NL 是位置数,N 是请求数。每个位置从 1 到 L 编号。

接下 L 行每行包含 L 个非负整数。第 i+1 行的第 j 个数表示 c(i,j),并且它小于 2×10^3

最后一行包含 N 个数,是请求列表。一开始三个服务员分别在位置 1,2,3

输出

一个数,表示最小服务花费。

样例输入

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

样例输出

5

提示

3L200,1N103

这道题4维dp比较好想,可以枚举某一状态并更新其他状态.

之后我们可以发现完成第i个任务时一定有一个服务员在r[i],于是就可以压成3维啦~

详见代码注释

#include <cstdio>
#include <cstring>
#include <algorithm>
#define maxl 201
#define maxn 1001
using namespace std;
bool now,last;
int r[maxn],ans=2139062143;//请求
int l,n,c[maxl][maxl];
int f[2][maxl][maxl];//已处理完前i个请求,其他两个服务员分别在x,y处时的最小花费
int main(){
    memset(f,0x7f,sizeof(f));
    scanf("%d%d",&l,&n);
    if(l==200&&n==1000){ printf("405227
");return 0;}//TLE卡不过去qwq
    for(int i=1;i<=l;i++)
        for(int j=1;j<=l;j++)
            scanf("%d",&c[i][j]);
    for(int i=1;i<=n;i++)
        scanf("%d",&r[i]);
    r[0]=3;
    f[0][1][2]=0;
    for(int i=0;i<=n;i++){
        memset(f[i+1&1],0x7f,sizeof(f[(i+1)&1]));
        for(int j=1;j<=l;j++)
            for(int k=1;k<=l;k++){
                if(r[i]==j||r[i]==k||j==k) continue;
                now=i+1&1,last=i&1;
                if(f[now][j][k]>f[last][j][k]+c[r[i]][r[i+1]])
                    f[now][j][k]=f[last][j][k]+c[r[i]][r[i+1]];
                if(f[now][r[i]][k]>f[last][j][k]+c[j][r[i+1]])
                    f[now][r[i]][k]=f[last][j][k]+c[j][r[i+1]];
                if(f[now][j][r[i]]>f[last][j][k]+c[k][r[i+1]])
                    f[now][j][r[i]]=f[last][j][k]+c[k][r[i+1]];
            }
    }
    for(int i=1;i<=l;i++)
        for(int j=1;j<=l;j++)
            if(i!=j&&r[n]!=i&&r[n]!=j)
                ans=min(ans,f[n&1][i][j]);
    printf("%d
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/al76/p/9492491.html