DPJSOI2010快递服务

Posted yimengshizai

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了DPJSOI2010快递服务相关的知识,希望对你有一定的参考价值。

【题目描述】

「飞奔」快递公司成立之后,已经分别与市内许多中小企业公司签订邮件收送服务契约。由于有些公司是在同一栋大楼内,所以「飞奔」公司收件的地点(收件点)最多只有m点 (1, 2, …, m),因此「飞奔」仅先行采购了三辆货車并聘用了三名司机,每天早上分别从收件地点 「1」, 「2」 及 「3」出发。而在与客户的服务契约中有明确订约:「飞奔」必须在客户提出邮件寄送要求的隔天派人至该公司(地点)收件。
为了能更有效率的服务客户并节省收件时间,该公司设立了收件服务登记网站,客户如有邮件需要寄送,必须在需要收件的前一天就先上网登记。为了节省油量,「飞奔」就利用晚上先行安排三位司机隔天的收件路线。每位司机至各地点收件的顺序应与各公司上网登记的顺序相符且必须能在最省油的情况下完成当天所有的收件服务。因此每位司机有可能需要在不同时间重复到同一地点收件,或不同的司机有可能需在不同的时间点前往同一地点收件。
如下面范例二(收件公司地点依序为: 4 2 4 1 5 4 3 2 1)所示,虽然司机1一开始就已经在收件地点「1」了,但是他却不能先把后面第四个登记的公司(地点「1」)邮件先收了再前往第一、第二、或第三个登记收件地点(地点「4」,「2」,「4」)收件。但是如果前三个登记收件的服务是由司机2或3來负责,则司机1就可以在地点「1」收了第四个登记的邮件后再前往后面所登记的地点收件。此外,在某些情况下,不一定每辆车都要收到货,也就是說,最佳收件方式也有可能是只需出动一或兩辆车去收货。请写一个程序來帮「飞奔」公司计算每天依预约顺序至各收件地点收件的最少总耗油量。 

【输入格式】

输入文件第一行有一个整数 m(3 ≤ m ≤ 200),代表「飞奔」公司收件的地点数,以1至m之间的整数代号來表示每个地点。
接下來的m行(第2到第m+1行),每行有m个整数,代表一个矩阵D。第 i +1行的第 j 个整数是D(i, j),D(i, j) 代表司机开车从收件点 i 到收件点 j 所需耗油量。最后有一行数串,数串之数字依序为前一天上网登记要求收件的公司地点代号,最多会有1000个收件请求。输入文件中任兩个相邻的整数都以一个空白隔开。 
注意:油量矩阵D满足三角不等式,也就是說 D(i, j) ≤ D(i, k) + D(k, j),1 ≤ i, j, k ≤ m。因此,每辆车前往下一个收件地点时一定是直接前往,不必先绕道至其它地点再抵达下个收件地点。

【输出格式】 

输出一个整数,代表收件所需最少总耗油量。

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

一类经典DP问题,我们思考可以发现对于第i次收货时而言,一定有一位司机在上一次的位置

于是我们可以枚举另两位司机的位置来进行转移,时间复杂度O(m^2*n)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
#include<iomanip>
using namespace std;
int n,m,c[205][205],f[2][205][205],q[1005];
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    for(int j=1;j<=n;j++) scanf("%d",&c[i][j]);
    while(~scanf("%d",&q[++m]));
    memset(f[0],0x3f,sizeof(f));
    q[0]=1;
    f[0][2][3]=0;
    for(int i=1;i<=m;i++)
    {
        int now=i&1;
        memset(f[now],0x3f,sizeof(f[now]));
        for(int j=1;j<=n;j++)
        for(int k=j+1;k<=n;k++)
        {
            if(q[i]!=j&&q[i]!=k)
            f[now][j][k]=min(f[now][j][k],f[now^1][j][k]+c[q[i-1]][q[i]]);
            int x1=min(k,q[i-1]),x2=max(k,q[i-1]);
            if(q[i]!=q[i-1]&&q[i]!=k)
            f[now][x1][x2]=min(f[now][x1][x2],f[now^1][j][k]+c[j][q[i]]);
            x1=min(j,q[i-1]),x2=max(j,q[i-1]);
            if(q[i]!=q[i-1]&&q[i]!=j)
            f[now][x1][x2]=min(f[now][x1][x2],f[now^1][j][k]+c[k][q[i]]);
        }
    }
    int ans=0x3f3f3f3f;
    for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++) ans=min(ans,f[m&1][i][j]);
    printf("%d",ans);
}

 





以上是关于DPJSOI2010快递服务的主要内容,如果未能解决你的问题,请参考以下文章

vs 2010代码片段

vc++2010设置和c#一样的代码段,vs2010 两下tab设置

有趣的 C++ 代码片段,有啥解释吗? [复制]

是否可以动态编译和执行 C# 代码片段?

此 Canon SDK C++ 代码片段的等效 C# 代码是啥?

在tablayout片段之间进行通信[重复]