哦对,在gmoj上是没有多组数据的。
题目链接:https://www.luogu.com.cn/problem/SP703,https://gmoj.net/senior/#main/show/1327
分析
我一开始居然想到一个一个贪心去了
四维DP比较好想:
f
[
i
]
[
x
]
[
y
]
[
z
]
f[i][x][y][z]
f[i][x][y][z]表示当前第i个任务,第一个员工在
x
x
x,第二个在
y
y
y,第三个在
z
z
z
但是时间空间都不行,怎么办?
然后可以发现这个题的一个性质,每次做任务后一定有一个员工停在p[i]处,所以就可以优化
设
f
[
i
]
[
x
]
[
y
]
f[i][x][y]
f[i][x][y]表示完成
i
i
i个目标,两个人停在
x
,
y
x,y
x,y位置,另一个人停在
p
[
i
]
p[i]
p[i]处,则有转移:
f
[
i
+
1
]
[
j
]
[
k
]
=
m
i
n
(
f
[
i
+
1
]
[
j
]
[
k
]
,
f
[
i
]
[
j
]
[
k
]
+
a
[
b
[
i
]
]
[
b
[
i
+
1
]
]
)
;
f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]+a[b[i]][b[i+1]]);
f[i+1][j][k]=min(f[i+1][j][k],f[i][j][k]+a[b[i]][b[i+1]]);
f [ i + 1 ] [ b [ i ] ] [ k ] = m i n ( f [ i + 1 ] [ b [ i ] ] [ k ] , f [ i ] [ j ] [ k ] + a [ j ] [ b [ i + 1 ] ] ) ; f[i+1][b[i]][k]=min(f[i+1][b[i]][k],f[i][j][k]+a[j][b[i+1]]); f[i+1][b[i]][k]=min(f[i+1][b[i]][k],f[i][j][k]+a[j][b[i+1]]);
f [ i + 1 ] [ j ] [ b [ i ] ] = m i n ( f [ i + 1 ] [ j ] [ b [ i ] ] , f [ i ] [ j ] [ k ] + a [ k ] [ b [ i + 1 ] ] ) ; f[i+1][j][b[i]]=min(f[i+1][j][b[i]],f[i][j][k]+a[k][b[i+1]]); f[i+1][j][b[i]]=min(f[i+1][j][b[i]],f[i][j][k]+a[k][b[i+1]]);
比赛的时候很自信交了这个代码,结果。。。MLE0分!与AK擦肩而过
一看数据范围65536KB,1000200200直接炸掉,于是要滚动数组。
看到转移只跟当前和上一个有关系,滚掉第一维。用奇偶性的原理滚动,具体见注释。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,q;
int a[201][201],b[2001],f[2][201][201];//滚动原理:奇偶性
int main()
{
cin>>n>>q;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&a[i][j]);
}
}
for(int i=1;i<=q;i++) cin>>b[i];
memset(f,0x3f3f3f3f,sizeof(f));
f[0][1][2]=0;
b[0]=3;
for(int i=0;i<q;i++)//这里是从i转到i+1,也可以从i-1转到i,方法相同
{
memset(f[i&1^1],0x3f3f3f3f,sizeof(f[i&1^1]));//清空i+1那一维
for(int j=1;j<=n;j++)
{
for(int k=1;k<=n;k++)
{
/*转移*/
if(b[i+1]!=j&&b[i+1]!=k)
f[i&1^1][j][k]=min(f[i&1^1][j][k],f[i&1][j][k]+a[b[i]][b[i+1]]);
if(b[i+1]!=k&&b[i+1]!=b[i])
f[i&1^1][b[i]][k]=min(f[i&1^1][b[i]][k],f[i&1][j][k]+a[j][b[i+1]]);
if(b[i+1]!=j&&b[i+1]!=b[i])
f[i&1^1][j][b[i]]=min(f[i&1^1][j][b[i]],f[i&1][j][k]+a[k][b[i+1]]);
}
}
}
int ans=2147483647;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
ans=min(ans,f[q&1][i][j]);
}
}
cout<<ans;
return 0;
}