考虑花费和员工的位置,请求的位置都有关,可以设状态f(i,x,y,z)表示完成了前i个请求,三个员工现在位于x,y,z三处的最小花费,由i可以方便地推到i+1
(DP既可以由i-1推到i,也可以是i推到i+1,灵活应用才能写好方程)
状态转移方程是:
f(i+1,x,y,z)=min(f(i+1,qi+1,y,z),f(i,x,y,z)+c(x,qi+1))
f
(
i
+
1
,
x
,
y
,
z
)
=
m
i
n
(
f
(
i
+
1
,
q
i
+
1
,
y
,
z
)
,
f
(
i
,
x
,
y
,
z
)
+
c
(
x
,
q
i
+
1
)
)
f(i+1,x,y,z)=min(f(i+1,x,qi+1,z),f(i,x,y,z)+c(y,qi+1))
f
(
i
+
1
,
x
,
y
,
z
)
=
m
i
n
(
f
(
i
+
1
,
x
,
q
i
+
1
,
z
)
,
f
(
i
,
x
,
y
,
z
)
+
c
(
y
,
q
i
+
1
)
)
f(i+1,x,y,z)=min(f(i+1,x,y,qi+1),f(i,x,y,z)+c(z,qi+1))
f
(
i
+
1
,
x
,
y
,
z
)
=
m
i
n
(
f
(
i
+
1
,
x
,
y
,
q
i
+
1
)
,
f
(
i
,
x
,
y
,
z
)
+
c
(
z
,
q
i
+
1
)
)
复杂度太高了,不过卡的好的话可以有60分~
但是我们发现员工的位置是根据请求而改变的,所以当第i个请求完成后,一定有一个员工位于位置 qi q i ,并且是哪个员工位于 qi q i 对答案是没有影响的
所以我们可以降低一维数组
设
f(i,x,y)
f
(
i
,
x
,
y
)
表示完成了前i个请求后,有一个员工位于
qi
q
i
处,另外两个员工位于x,y处的最小花费
设
q0
q
0
为3,这样就可以从i=0推到i=n
注意一点,对于状态转移方程:
f(i+1,x,qi)=min(f(i+1,x,qi),f(i,x,qi)+c(y,qi+1))
f
(
i
+
1
,
x
,
q
i
)
=
m
i
n
(
f
(
i
+
1
,
x
,
q
i
)
,
f
(
i
,
x
,
q
i
)
+
c
(
y
,
q
i
+
1
)
)
表示,y位置的员工前往了
qi+1
q
i
+
1
位置,并且x,qi不动,所以i+1处的状态依然是x,qi 而不是 x,
qi+1
q
i
+
1
但是这样还!不!够!
我们发现内存仍然不够用,需要再优化一维
考虑到第i个阶段只和第i-1阶段有关,我们可以开f[2][201][201]
设k=0,由k^1来变换k
并且在这样滚动的时候需要想好k和k^1所代表的含义
我设k为下一个请求,k^1为已完成的最后一个请求,那么递推就是由k^1推到k的,并且最终答案也是min(f[k][x][y])
在取最终答案时不能把f[k]和f[k^1]比较
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int MAXN = 100000 + 10;
int c[210][210],l,n,que[1010],qi=3,ans=0x3f3f3f3f + 200;
int f[2][201][201];
int main() {
scanf("%d %d", &l, &n);
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", que + i);
memset(f,0x3f,sizeof(f));
f[0][1][2] = 0;
int k = 0;
for(int i=0; i<n; i++) {
int x, y;
k^=1;
for(int j=1; j<=l; j++)
for(int t=1; t<=l; t++)
f[k][j][t] = 0x3f3f3f3f;//在统计时要对即将要更新的阶段重新赋最大值
for(int x=1; x<=l; x++)
for(int y=1; y<=l; y++) {
if(x==y || y==x) continue;
f[k][x][y] = min(f[k][x][y],f[k^1][x][y] + c[qi][que[i+1]]);
f[k][qi][y] = min(f[k][qi][y],f[k^1][x][y] + c[x][que[i+1]]);
f[k][x][qi] = min(f[k][x][qi],f[k^1][x][y] + c[y][que[i+1]]);
}
qi = que[i+1];
}
for(int x=1; x<=l; x++)
for(int y=1; y<=l; y++)
ans = min(ans, f[k][x][y]);
printf("%d\n", ans);
return 0;
}