Sicily 1419 On the run 动态规划的应用

对于这题一开始的思路走了误区——尝试遍历完数轴上所有的点取最小的总路程,而后发现这个其实和题意是两回事。

主要是某一个人的不满意值(等待时间)是和前面所到达过的每一个人的不满意值都关联的。

考虑无论如何只有两种情况:从出发点向上走或向下走。然后从只有两个住户的情况开始考虑解法:

用两个数组d_down[ i ][ j ]和d_up[ i ][ j ]分别表示从出发点出发,最低楼层到达了i楼,最低楼层到达了j楼的总的不满意值。其中d_down表示最后停在i,d_up表示最后停在j(i一定小于j并且i、j之间所有点都已遍历)。那么我们要求的就是d_down[ 0 ][ all-1 ]和d_up[ 0 ][ all-1 ]的最小值。

对用户楼层进行排序后我们很容易就能找到送奶工的位置start,自然d_down[ start ][ start ]和d_up[ start ][ start ]都是0。然后各自从start开始,往下递减i,往上递增j来确定每一个点的不满意值:

d_down[down][up]=min{ d_down[down+1][up]+wait_time_1,d_up[down+1][up]+wait_time_2 }

d_up[down][up]=min{ d_down[down][up-1]+wait_time_1,d_up[down][up-1]+wait_time_2 }

其中的wait_time根据不同的情况确定。

还有个要注意的是在输入用户楼层时最后还要输入送奶工的出发点,才能在后续排序中查找定位到。用a[ all++ ] 的方式同时使总值自增较为方便。

代码如下:


// Problem#: 1419
// Submission#: 3823374
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include<iostream>
#include<cstring>
using namespace std;

int d_down[1006][1006],d_up[1006][1006],node[1006];

void Sh_sort(int array[],int size)//Shell sort
{
    int t,j,temp;
    for(int t=size/2;t>=1;t/=2)
    {
        for(int i=t;i<size;i++)
        {
            temp=array[i];
            j=i-t;
            while(array[j]>temp&&j>=0)
            {
                array[j+t]=array[j];
                j=j-t;
            }
            array[j+t]=temp;
        }
    }
}

int Get_min(int a,int b)
{
    if(a<b)
    {
        return a;
    }
    else return b;
}

int Get_start(int array[],int size,int start)
{
    int result;
    for(int i=0;i<size;i++)
    {
        if(array[i]==start)
        {
            result=i;
            break;
        }
    }
    return result;
}

int main()
{
    int cases;
    cin>>cases;
    while(cases--)
    {
        int sum,home;
        cin>>sum>>home;
        for(int i=0;i<sum;i++)
        {
            cin>>node[i];
        }
        node[sum++]=home;
        
        Sh_sort(node,sum);      //对用户楼层先行排序
        int start,wait_time_1,wait_time_2,result;
        start=Get_start(node,sum,home);
        
        memset(d_down,100,sizeof(d_down));
        memset(d_up,100,sizeof(d_up));
        
        d_down[start][start]=0;
        d_up[start][start]=0;
        
        for(int down=start;down>=0;down--)
        {
            for(int up=start;up<sum;up++)
            {
                if(down<start)
                {
                    wait_time_1=(node[down+1]-node[down])*(sum-(up-down));
                    wait_time_2=(node[up]-node[down])*(sum-(up-down));
                    
                    d_down[down][up]=Get_min(d_down[down+1][up]+wait_time_1,
                                         d_up[down+1][up]+wait_time_2);
                }
                if(up>start)
                {
                    wait_time_1=(node[up]-node[down])*(sum-(up-down));
                    wait_time_2=(node[up]-node[up-1])*(sum-(up-down));
                    
                    d_up[down][up]=Get_min(d_down[down][up-1]+wait_time_1,
                                           d_up[down][up-1]+wait_time_2);
                }
            }
        }
        
        result=Get_min(d_down[0][sum-1],d_up[0][sum-1]);
        cout<<result<<endl;
    }
}                                 



为了一贯的main函数简洁和复习之前知识,在这片代码里有一大堆废话,主要算法get到了就可以了,有时能用标准库的函数还是多用为好。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值