SP703 SERVICE_Mobile Service[动态规划]

SERVICEMobileServiceSERVICE-Mobile-Service


Description

链接


Solution

以三个员工的位置作为状态, 第ii次询问作为阶段
可以得出 DpDp 雏形
dp[i,x,y,z]dp[i, x, y, z]表示完成第ii次询问, 且员工位置分别在x,y,zx, y, z时的最小花费
考虑其能够更新的状态 :

  1. dp[i+1,Qi+1,y,z]dp[i+1, Q_{i+1}, y, z]
  2. dp[i+1,x,Qi+1,z]dp[i+1, x, Q_{i+1}, z]
  3. dp[i+1,x,y,Qi+1]dp[i+1, x, y, Q_{i+1}]

但是以此作为状态的时空复杂度为O(QN3)O(Q*N^3), 无论是空间和时间都无法承受 .
这时可以观察到, 当完成上一个询问时, 已经有一个员工位置确定下来了.
于是可以设dp[i,x,y]dp[i, x, y]表示完成第ii次询问, 且员工位置分别在x,y,Quei1x, y, Que_{i-1}时的最小花费
转移时同理 .


Attention

以从 xxQueiQue_i 位置为例

容易写成
dp[i,Quei,y]=min{dp[i1,x,y]+co[x,Quei]}dp[i, Que_{i}, y] = min{ dp[i-1, x, y] + co[x, Que_i] }
正确的却是
dp[i,Quei1,y]=min{dp[i1,x,y]+co[x,Quei]}dp[i, Que_{i-1}, y] = min{ dp[i-1, x, y] + co[x, Que_i] }

错误的原因就在于没有考虑所要更新的状态会去更新哪些状态
由于省略了一维, 在将一个员工 H 转移到新位置的时,
H 对于i+1i+1询问来说, 相当于那个省略的一维,
那个在 ii 询问中省略的 P员工, 对于i+1i+1询问来说, 却是没有省略的那个员工,
所以转移新位置时将 P员工 放在已知的那个位置


Code

#include<bits/stdc++.h>
#define reg register

int read(){
        int s = 0, flag = 1;
        char c;
        while((c=getchar()) && !isdigit(c))
                if(c == '-'){ flag = -1, c = getchar(); break ; }
        while(isdigit(c)) s = s*10 + c-'0', c = getchar();
        return s * flag;
}

int N, M;
int co[205][205];
int dp[1005][205][205];
int Que[1005];

void Work(){
        N = read(), M = read();
        for(reg int i = 1; i <= N; i ++)
                for(reg int j = 1; j <= N; j ++) co[i][j] = read();
        for(reg int i = 1; i <= M; i ++) Que[i] = read();
        memset(dp, 0x3f, sizeof dp);
        Que[0] = 3, dp[0][1][2] = 0;
        int Ans = 0x3f3f3f3f;
        for(reg int i = 1; i <= M; i ++)
                for(reg int x = 1; x <= N; x ++)
                        for(reg int y = 1; y <= N; y ++){
                                if(Que[i-1] == x || Que[i-1] == y || x == y) continue ;
                                if(Que[i] != y && Que[i] != Que[i-1]){
                                        int temp = dp[i][Que[i-1]][y] = std::min(dp[i][Que[i-1]][y], dp[i-1][x][y] + co[x][Que[i]]);
                                        if(i == M) Ans = std::min(Ans, temp);
                                }
                                if(Que[i] != x && Que[i] != Que[i-1]){
                                        int temp = dp[i][x][Que[i-1]] = std::min(dp[i][x][Que[i-1]], dp[i-1][x][y] + co[y][Que[i]]);
                                        if(i == M) Ans = std::min(Ans, temp);
                                }
                                if(Que[i] != x && Que[i] != y){
                                        int temp = dp[i][x][y] = std::min(dp[i][x][y], dp[i-1][x][y] + co[Que[i-1]][Que[i]]);
                                        if(i == M) Ans = std::min(Ans, temp);
                                }
                        }
        printf("%d
", Ans);
}

int main(){
        int T = read();
        while(T --) Work();
        return 0;
}
原文地址:https://www.cnblogs.com/zbr162/p/11822656.html