hrbust 1331 ACM之路 邂逅DP【dp】

ACM之路 邂逅DP

Time Limit: 1000 MS

Memory Limit: 65536 K

 

Total Submit: 158(51 users)

Total Accepted: 67(46 users)

Rating: 

Special Judge: No

 

Description

 

MM迷上了ACM,不可救药。。。

算法绝非一天两天就能学好,需要不断的看书学习,不断的敲代码,不断的看书学习,不断的敲代码。。。

这是一条没有尽头的路。。。

 

尼玛的搞ACM的伤不起啊!!!

详情见:搞ACM的你伤不起 http://heliang.me/blog/?p=548

 

最近又搞上了动态规划,这动态规划伤不起啊!

《算法导论》的第一个个动态规划就老长一篇了,MM看得头大,就跑过去问GG了。

GG看着MM粉红可爱的脸蛋,瞬间激情燃烧,充满活力,想着:我不会动态规划也得会了。

下面是《算法导论》上的第一个动态规划问题。

 

 

装配线问题

 

Colonel汽车公司在有两条装配线的工厂内生产汽车,一个汽车底盘在进入每一条装配线后,在每个装配站会在汽车底盘上安装不同的部件,最后完成的汽车从装配线的末端离开。如下图1所示。(竟然粘贴不上来,题目地址:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1331)

                      

                                         装配线示意图

每一条装配线上有n个装配站,编号为j=1,2,...,n,将装配线i(i为1或2)的第j个装配站表示为S(i,j)。

装配线1的第j个站S(1,j)和装配线2的第j个站S(2,j)执行相同的功能。

然而这些装配站是在不同的时间建造的,并且采用了不同的技术,因此,每个站上完成装配所需要的时间也不相同,即使是在两条装配线上相同位置的装配站也是这样。

把每个装配站上所需要的装配时间记为a(i,j),并且,底盘进入装配线i需要的时间为e(i),离开装配线i需要的时间是x(i)。

正常情况下,底盘从一条装配线的上一个站移到下一个站所花费的时间可以忽略,但是偶尔也会将未完成的底盘从一条装配线的一个站移到另一条装配线的下一站,比如遇到紧急订单的时候。

假设将已经通过装配站S(i,j)的底盘从装配线i移走到另一条装配线所花费的时间为t(i,j),现在的问题是要确定在装配线1内选择哪些站以及在装配线2内选择哪些站,以使汽车通过工厂的总时间最小。

 

GG思考了一会,然后耐心的给MM解答了。。。

Input

有多组测试数据,对于每组测试数据,第1行为一个整数n(0<n<=100000),表示有n个装配站,第2行和第3行是装配线1和2的入站时间、站1到站n的装配时间,出站时间,每行n+2个整数(<=1000000)。第4行和第5行是装配线1和2移动到另外一条装配线的下一个站的时间,每行有n-1个整数(<=100)。

Output

对于每组测试数据输出一行,包含一个整数,需要的最少装配时间。

Sample Input

6

2 7 9 3 4 8 4 3

4 8 5 6 4 5 7 2

2 3 1 3 4

2 1 2 2 1

Sample Output

38

Source

2012 Spring Contest 5 - Binary Search, Greedy, DP

Author

《算法导论》

 

题目连接:http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1331


思路:题目大意说的很清楚,这里直接分析解题方法。


首先设dp【2】【i】,dp【1】【i】表示第一行上边连接到i这个位子用的最小消耗,dp【2】【i】则表示第四行上边连接到i这个位子的最小消耗。根据题中给出的图,发现除了起点和第一个点以及最后一个点之外,都有两种来到这个点的方法。一个是从左边过来,一个是从左下过来,辣么不难推出状态转移方程:


dp【1】【i】=min(dp【1】【i-1】,dp【2】【i-1】+a【3】【i-1】过来消耗的那个值)+a【1】【i】(当前节点值);

dp【2】【i】=min(dp【2】【i-1】,dp【1】【i-1】+a【2】【i-1】过来消耗的那个值)+a【1】【i】(当前节点值);


对于i==2的时候,和i==n+2的时候,dp【1/2】【i】=dp【1/2】【i-1】+a【1/4】【i】;


注意的点:数据值比较大,需要用long long int

思路构建完毕,上代码.

AC代码:

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#define ll long long int
ll a[5][100005];
ll dp[3][100005];
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        memset(dp,0,sizeof(dp));
        memset(a,0,sizeof(a));
        for(int j=1; j<=n+2; j++)
        {
            scanf("%lld",&a[1][j]);
        }
        for(int j=1; j<=n+2; j++)
        {
            scanf("%lld",&a[4][j]);
        }
        for(int j=2; j<=n; j++)
        {
            scanf("%lld",&a[2][j]);
        }
        for(int j=2; j<=n; j++)
        {
            scanf("%lld",&a[3][j]);
        }
        for(int i=1;i<=n+2;i++)
        {
            if(i==1)
            {
                dp[1][i]=a[1][i];
                dp[2][i]=a[4][i];
                continue;
            }
            if(i==2||i==n+2)
            {
                dp[1][i]=dp[1][i-1]+a[1][i];
                dp[2][i]=dp[2][i-1]+a[4][i];
                continue;
            }
            dp[1][i]=min(dp[1][i-1],dp[2][i-1]+a[3][i-1])+a[1][i];
            dp[2][i]=min(dp[2][i-1],dp[1][i-1]+a[2][i-1])+a[4][i];
        }
        printf("%lld\n",min(dp[1][n+2],dp[2][n+2]));
    }
}










  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值