• 题解 SP703 【SERVICE


    Link

    SP703 SERVICE - Mobile Service

    Solve

    为了计算指派服务员的花费,就必须知道状态转移时每个服务员的位置,于是我们就很容易列出一个(DP)状态,设(F[i][j][k][z])表示完成了前(i)个任务,三个员工分别位于(j,k,z)的位置时的最小花费。

    转移方程也很容易的推出

    (F[i+1][p[i+1]][k][z]=min(F[i+1][p[i+1]][k][z],F[i][j][k][z]+cost(j,p[i+1])))

    (F[i+1][j][p[i+1]][z]=min(F[i+1][j][p[i+1]][z],F[i][j][k][z]+cost(k,p[i+1])))

    (F[i+1][j][k][p[i+1]]=min(F[i+1][j][k][p[i+1]],F[i][j][k][z]+cost(z,p[i+1])))

    但是我们发现这个算法的复杂度在(1000 ast 200^3),不能承受,要想办法降维,我们发现,一个服务员不会在乱跑,当枚举到(p[i])时肯定有个服务员在(p[i-1])的位置,我们就可以去掉一维,处于(p[i])位置的服务员对于(DP)来说没有用的

    我们修改定义,(F[i][j][k])表示完成了前(i)个请求,其中一个服务员于(p[i]),另外两个服务员的位置分别位于(j,k),三种转移分别是让位于(p[i],j,k)的服务员前往(p[i+1])

    (F[i+1][j][k]=min(F[i+1][j][k],F[i][j][k]+cost(p[i],p[i+1])))

    (F[i+1][p[i]][k]=min(F[i+1][p[i]][k],F[i][j][k]+cost(j,p[i+1])))

    (F[i+1][j][p[i]]=min(F[i+1][j][p[i]],F[i][j][k]+cost(k,p[i+1])))

    因为两个服务员是不可以在同一个位置的,所以在转移的时候要判断一下服务员和要去的位置是否相同。

    考虑初始,设(p[0]=3),(F[0][1][2]=0),答案(max(F[N][1-L][1-L]))最后扫一下就可以了

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int maxl=205,maxn=1005;
    int T,L,N,w[maxl][maxl],p[maxn];
    LL F[maxn][maxl][maxl],ans;
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
    	return ret*f;
    }
    int main(){
    	T=read();
    	while(T--){
    		L=read();N=read();
    		memset(F,63,sizeof F);ans=F[0][0][0];
    		p[0]=3;F[0][1][2]=0;
    		for(int i=1;i<=L;i++)
    			for(int j=1;j<=L;j++)w[i][j]=read();
    		for(int i=1;i<=N;i++)p[i]=read();
    		for(int i=0;i<N;i++)
    		for(int j=1;j<=L;j++)
    		for(int k=1;k<=L;k++){
    			if(j^p[i+1]&&k^p[i+1])F[i+1][j][k]=min(F[i+1][j][k],F[i][j][k]+w[p[i]][p[i+1]]);
    			if(k^p[i+1]&&p[i]^p[i+1])F[i+1][p[i]][k]=min(F[i+1][p[i]][k],F[i][j][k]+w[j][p[i+1]]);
    			if(j^p[i+1]&&p[i]^p[i+1])F[i+1][j][p[i]]=min(F[i+1][j][p[i]],F[i][j][k]+w[k][p[i+1]]);
    		}
    		for(int i=1;i<=L;i++)
    		for(int j=1;j<=L;j++){
    			ans=min(ans,F[N][i][j]);
    			ans=min(ans,F[N][p[N]][j]);
    			ans=min(ans,F[N][j][p[N]]);
    		}
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    『ORACLE』 DG切换主备库角色(11g)
    Java基础语法(三)---数组
    JDK安装与配置详细图文教程
    谁把20岁上下的你给洗脑了
    看看已堕落的自己
    关于Git
    自定义UIDatePikerView
    细节关注(持续更新。。。)
    如何生成圆形的图片
    高效使用你的Xcode
  • 原文地址:https://www.cnblogs.com/martian148/p/13905285.html
Copyright © 2020-2023  润新知