题目:我是超链接
题解:
可以发现这是一道dp题目,设计状态f[i][j][k][l]表示第i请求时,服务员分别位于j,k,l位置,发现转移也很简单,可以从j||k||l转移到b[i],而且这一请求的转移只会是上一个请求,所以可以用滚动数组优化,但我们发现这样超低的效率是O(nl^3),如何优化?
因为这一时刻一结束,一定有一个服务员位于b[i],所以上一时刻的服务员位置为j,k,b[i-1]这样枚举可以少上一维,那我们设计状态f[i][j][k]表示第i个请求时,服务员位于j,k,消去的那一维在b[i-1],转移很好写出
其实还有一个优化,我们发现f[2][1][3]和f[2][3][1]表示一个意思,可以省去一些,使光存储j<k的状态
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#define INF 1e9
using namespace std;
int a[205][205],b[1005],f[2][205][205];
int main()
{
int l,n,i,j,k;
scanf("%d%d",&l,&n);
for (i=1;i<=l;i++)
for (j=1;j<=l;j++) scanf("%d",&a[i][j]);
for (i=1;i<=n;i++) scanf("%d",&b[i]);
memset(f,0x7f,sizeof(f));
if (b[1]!=2 && b[1]!=3) f[1][2][3]=a[1][b[1]];
if (b[1]!=1 && b[1]!=3) f[1][1][3]=a[2][b[1]];
if (b[1]!=1 && b[1]!=2) f[1][1][2]=a[3][b[1]];
for (i=2;i<=n;i++)//坐标分别为j,k,b[i-1],jk代表不在b[i-1]的那两个人的位置
{
memset(f[i%2],0x7f,sizeof(f[i%2]));
for (j=1;j<=l;j++)
for (k=j+1;k<=l;k++)
{
if (j!=b[i] && k!=b[i]) f[i%2][j][k]=min(f[i%2][j][k],f[(i-1)%2][j][k]+a[b[i-1]][b[i]]);
if (j!=b[i] && b[i-1]!=b[i])
{
if (b[i-1]>j) f[i%2][j][b[i-1]]=min(f[i%2][j][b[i-1]],f[(i-1)%2][j][k]+a[k][b[i]]);
else f[i%2][b[i-1]][j]=min(f[i%2][b[i-1]][j],f[(i-1)%2][j][k]+a[k][b[i]]);
}
if (k!=b[i] && b[i-1]!=b[i])
{
if (b[i-1]>k) f[i%2][k][b[i-1]]=min(f[i%2][k][b[i-1]],f[(i-1)%2][j][k]+a[j][b[i]]);
else f[i%2][b[i-1]][k]=min(f[i%2][b[i-1]][k],f[(i-1)%2][j][k]+a[j][b[i]]);
}
}
}
int ans=INF;
for (i=1;i<=l;i++)
for (j=i+1;j<=l;j++)
if (i!=b[n] && j!=b[n])
ans=min(ans,f[n%2][i][j]);
printf("%d",ans);
}
总结:两个优化