AcWing 274. 移动服务

AcWing

思路

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);
}
posted @ 2019-10-03 22:54  G_A_TS  阅读(353)  评论(0编辑  收藏  举报