zoukankan      html  css  js  c++  java
  • [CH5102]Mobile Service

    原题

    题目描述:

    一个公司有三个移动服务员,最初分别在位置1,2,3处。
    如果某个位置(用一个整数表示)有一个请求,那么公司必须指派某名员工赶到那个地方去。某一时刻只有一个员工能移动,且不允许在同样的位置出现两个员工。从 (p)(q) 移动一个员工,需要花费 (c(p,q))。这个函数不一定对称,但保证 (c(p,p)=0)
    给出N个请求,请求发生的位置分别为 (p_1) ~ (p_N)。公司必须按顺序依次满足所有请求,目标是最小化公司花费,请你帮忙计算这个最小花费。(N≤1000),位置是1~200的整数。

    输入格式

    第一行有两个整数 (L,N(3le Lle 200, 1le Nle 1000))(L) 是位置数;(N) 是请求数。每个位置从 (1)(L) 编号。下 (L) 行每行包含 (L) 个非负整数。第 (i+1) 行的第 (j) 个数表示 (c(i,j)) ,并且它小于 (2000)。最后一行包含 (N) 个数,是请求列表。一开始三个服务员分别在位置 (1,2,3)

    输出格式

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

    样例输入

    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
    

    ( ext{Solution:})

    我们很容易想到用一个四元组 ((i, x, y, z)) 来表示一个状态,即已经处理好 (i) 个请求,三个服务员的位置是 (x,y,z) , 显然有转移:

    [egin{aligned} F[i + 1,p_{i + 1]},y,z] &= min(F[i,x,y,z] + c[x,p_{i+1}])\ &dots end{aligned} ]

    然而这样的状态太多需要枚举 (1000 imes 200^3) 次,所以我们想办法设计一种状态更少的能够覆盖整个状态空间的"维度集合"

    仔细观察可以发现,在状态 ((i,x,y,z)) 中,一定会有 (x)(y)(z) 中的一个等于 (p_i), 所以我们可以通过枚举 (i) 来确定两维状态,而剩下的两维状态就直接枚举,枚举规模降低到了 (1000 imes 200^2)

    所以用三元组 ((i, x, y)) 表示处理好前i个请求,一个服务员位于 (p_i), 另外两个分别位于 (x,z)

    [egin{aligned} F[i+1,x,y]&=min(F[i,x,y]+c[p_i,p_{i+1}])\ F[i+1,p_i,y]&=min(F[i,x,y]+c[x,p_{i+1}])\ F[i+1,x,p_i]&=min(F[i,x,y]+c[y,p_{i+1}]) end{aligned} ]

    第一个式子很好理解,第二个式子表示从 ((i,p_i,x,y) o (i+1,p_i,p_{i+1},y)), 想想状态的定义就知道为什么转移后 (x) 变成 (p_i) 了, 第三个式子同理。

    ( ext{这题告诉我们:})

    对于线性的 ( ext{dp}) ,一般先枚举阶段再枚举状态最后枚举决策,枚举顺序一定不能混淆,但是在状态表示清晰的的时候往往需要枚举的维数也多从而导致复杂度过高,所以需要仔细观察题目所给的条件,考虑不同维度之间的状态是否能由其他维度的状态或阶段推出 ,从而减少枚举的维度。

    #include <iostream>
    #include <cstring>
    
    int n, m;
    int f[1020][202][202], c[202][202], p[1020];
    void chkmin(int &a, int b) 
    { if (a > b) a = b; }
    
    int main()
    {
    
        std::cin >> n >> m;
        for (int i = 1; i <= n; ++ i)
            for (int j = 1; j <= n; ++ j)
                std::cin >> c[i][j];
        for (int i = 1; i <= m; ++ i)
            std::cin >> p[i];
    
        memset(f, 0x3f, sizeof f);
        f[0][1][2] = 0; p[0] = 3;
        for (int i = 0; i < m; ++ i) 
            for (int j = 1; j <= n; ++ j)
                for (int l = 1; l <= n; ++ l)
                {
                    if (f[i][j][l] == 0x3f3f3f3f) continue;
                    if (p[i + 1] != j and p[i + 1] != l)
                        chkmin(f[i + 1][j][l], f[i][j][l] + c[p[i]][p[i + 1]]);
                    if (p[i + 1] != l and p[i + 1] != p[i])
                        chkmin(f[i + 1][p[i]][l], f[i][j][l] + c[j][p[i + 1]]);
                    if (p[i + 1] != j and p[i + 1] != p[i])
                        chkmin(f[i + 1][j][p[i]], f[i][j][l] + c[l][p[i + 1]]);
                }
        int ans = 0x3f3f3f3f;
        for (int i = 1; i <= n; ++ i)
            for (int j = 1; j <= n; ++ j)
                chkmin(ans, f[m][i][j]);
        std::cout << ans << std::endl;
    }
    
  • 相关阅读:
    swift判断是不是刘海屏
    swift 获取缓存 删除缓存
    iOS推送接入 获取devicetoken 证书报错解决方法:Code=3000 "未找到应用程序的“aps-environment”的授权字符串" 解决办法
    iOS 判断设备网络是否使用代理
    iOS接入阿里云一键登录,号码认证
    python代码实现回归分析--线性回归
    【优博微展2019】王景璟:异构信息网络协同优化基础理论和应用 开题报告-毕业答辩
    摘要与引言基本要求1
    深度学习理论与架构最新进展综述论文,66页pdf,333篇参考文献
    论文引言的逻辑结构
  • 原文地址:https://www.cnblogs.com/cnyali-Tea/p/10499516.html
Copyright © 2011-2022 走看看