AcWing 274. 移动服务
思路
dp
关于dp
dp分为状态构造与状态转移(?)
状态构造
状态集合角度,分析题目状态,本题可以想到(i,x,y,z)为完成第\(i\)个时各服务员分别在x,y,z时的花费之和,f[i][x][y][z]为其最小值
然后发现当完成第\(i\)个时必有一个在第\(i\)个请求的位置,于是减去一维得到(i,x,y)为完成第\(i\)个时闲置的服务员在x,y时的花费之和,f[i][x][y]为其最小值
状态转移
dp其实可以理解为在拓扑图上的操作
一般线性dp题有两种转移:
从已知拓展当前
略,大部分(?)dp题的解法
从当前拓展未知
本题用这种方法的原因是能影响当前状态的状态太多,而当前影响未来状态却只有整齐的3种
即
f[i+1][x][y]=min(f[i+1][x][y],f[i][x][y]+w[z][p[i+1]]);//p[i]为第i个请求的位置
f[i+1][x][z]=min(f[i+1][x][z],f[i][x][y]+w[y][p[i+1]]);
f[i+1][y][z]=min(f[i+1][y][z],f[i][x][y]+w[x][p[i+1]]);
Code
#include<bits/stdc++.h>
using namespace std;
int n,m,w[210][210],f[1010][210][210],p[1010],ans=0x7FFFFFFF;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
scanf("%d",&w[i][j]);
}
}
for(int i=1;i<=m;i++)
scanf("%d",&p[i]);
p[0]=3;
memset(f,0x3f,sizeof(f));
f[0][1][2]=0;
for(int i=0;i<m;i++)
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
{
int z=p[i];
if(x==y||y==z||x==z)
continue;
f[i+1][x][y]=min(f[i+1][x][y],f[i][x][y]+w[z][p[i+1]]);
f[i+1][x][z]=min(f[i+1][x][z],f[i][x][y]+w[y][p[i+1]]);
f[i+1][y][z]=min(f[i+1][y][z],f[i][x][y]+w[x][p[i+1]]);
}
for(int x=1;x<=n;x++)
{
for(int y=1;y<=n;y++)
{
int z=p[m];
if(x==y||x==z||y==z)
continue;
ans=min(ans,f[m][x][y]);
}
}
printf("%d",ans);
}