【线性dp】Contest Hunter_5102 Mobile Service

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SSL_hzb/article/details/82463253

题意

有三个服务员,最初分别在位置 1 2 3 处。
L 个位置,其中位置 x 到位置 y 的距离是 c ( x , y ) ,这个函数不一定对称,但满足 c ( x , x ) = 0
现在有 N 个请求,分别是 P 1 P n 公司要按照这个顺序依次满足所有要求,求最小花费。

思路

我们可以用 f [ i ] [ x ] [ y ] 表示完成了前 i 个请求,其中有两个服务员分别在位置 x 和位置 y ,剩下的一个服务员在 P i 的最小花费。
我们让这三个服务员分别转移到 P i + 1 ,可以得出动态转移方程:
f [ i + 1 ] [ x ] [ y ] = m i n ( f [ i + 1 ] [ x ] [ y ] , f [ i ] [ x ] [ y ] + c ( p i , p i + 1 ) )
f [ i + 1 ] [ p i ] [ y ] = m i n ( f [ i + 1 ] [ p i ] [ y ] , f [ i ] [ x ] [ y ] + c ( p i , p i + 1 ) )
f [ i + 1 ] [ x ] [ p i ] = m i n ( f [ i + 1 ] [ x ] [ p i ] , f [ i ] [ x ] [ y ] + c ( y , p i + 1 ) )
注意转移的时候判断位置不要重复。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

int cost[201][201], f[1001][201][201], ask[1001];
int L, N, ans = 2147483647;

void dp() {
    memset(f, 127/3, sizeof(f));
    f[0][1][2] = 0;
    ask[0] = 3;
    for (int i = 0; i < N; i++)
    {
        for (int x = 1; x <= L; x++)
            for (int y = 1; y <= L; y++)
            {
                if (x != ask[i + 1] && y != ask[i + 1])
                    f[i + 1][x][y] = min(f[i + 1][x][y], f[i][x][y] + cost[ask[i]][ask[i + 1]]);
                if (ask[i] != ask[i + 1] && y != ask[i + 1])
                    f[i + 1][ask[i]][y] = min(f[i + 1][ask[i]][y], f[i][x][y] + cost[x][ask[i + 1]]);
                if (x != ask[i + 1] && ask[i] != ask[i + 1])
                    f[i + 1][x][ask[i]] = min(f[i + 1][x][ask[i]], f[i][x][y] + cost[y][ask[i + 1]]);
            }
    }   
    for (int x = 1; x <= L; x++)
        for (int y = 1; y <= L; y++)
            ans = min(ans, f[N][x][y]);
    printf("%d", ans);
}

int main() {
    scanf("%d %d", &L, &N);
    for (int i = 1; i <= L; i++)
        for (int j = 1; j <= L; j++)
            scanf("%d", &cost[i][j]);
    for (int i = 1; i <= N; i++) 
        scanf("%d", &ask[i]);
    dp();
}

猜你喜欢

转载自blog.csdn.net/SSL_hzb/article/details/82463253