【CH5102】Mobile Service

线型动态规划的好题……

分析题意,不难设计出状态:f[i][x][y][z]表示完成第i个任务后,三个人分别在x,y,z位置时的花费。但是这样的状态时间与空间都无法承受,不可行。

再次考虑:当完成第i个任务后,其中一人必定在p[i]上,因此状态可以减少一维:f[i][x][y]表示完成第i个任务后,另外两个人(除了这一步移动的到p[i]的那个人)分别在x,y位置时的花费。

考虑状态转移:若当前位于状态f[i][x][y],当前要处理第i+1个任务,要去往p[i+1]位置。设当前位于p[i]的那个人为z。c数组表示花费(见题目描述)。

1、如果让x去p[i+1](y,z不在那里),则f[i+1][y][z]=min(f[i+1][y][z],f[i][x][y]+c[x][p[i+1]]).

2、如果让y去p[i+1](x,z不在那里),则f[i+1][x][z]=min(f[i+1][x][z],f[i][x][y]+c[y][p[i+1]]).

3、如果让z去p[i+1](x,y不在那里),则f[i+1][x][y]=min(f[i+1][x][y],f[i][x][y]+c[z][p[i+1]]).

另外,我们发现第i个任务的状态只能从第i-1个任务的状态转移过来,也就是说我们可以用滚动数组优化空间,只存i和i-1,每次计算都覆盖掉原来的状态。

这样我们就不难得出正解。

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 using namespace std;
 5 int n,m;
 6 int c[210][210],ans,p[1010];
 7 int f[2][210][210];
 8 int main() {
 9     scanf("%d%d",&m,&n);
10     for(int i=1;i<=m;i++)
11         for(int j=1;j<=m;j++)
12             scanf("%d",&c[i][j]);
13     for(int i=1;i<=n;i++) scanf("%d",&p[i]);
14     p[0]=3;
15     memset(f,0x3f,sizeof(f));
16     f[0][1][2]=0;
17     for(int i=1;i<=n;i++) {
18         for(int x=1;x<=m;x++) {
19             for(int y=1;y<=m;y++)
20                 if(f[i-1&1][x][y]!=0x3f3f3f3f) {
21                     int z=p[i-1];
22                     if(x!=p[i]&&y!=p[i]) f[i&1][x][y]=min(f[i&1][x][y],f[i-1&1][x][y]+c[z][p[i]]);
23                     if(x!=p[i]&&z!=p[i]) f[i&1][x][z]=min(f[i&1][x][z],f[i-1&1][x][y]+c[y][p[i]]);
24                     if(y!=p[i]&&z!=p[i]) f[i&1][y][z]=min(f[i&1][y][z],f[i-1&1][x][y]+c[x][p[i]]);
25                     f[i-1&1][x][y]=0x3f3f3f3f;
26                 }
27         }
28     }
29     ans=1<<30;
30     for(int i=1;i<=m;i++)
31         for(int j=1;j<=m;j++)
32             ans=min(ans,f[n&1][i][j]);
33     printf("%d
",ans);
34     return 0;
35 }
AC Code
原文地址:https://www.cnblogs.com/shl-blog/p/10660405.html