ACM之路 邂逅DP |
||||||
|
||||||
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])); } }