1. 程式人生 > >動態規劃(DP問題)裝配線問題(C++)

動態規劃(DP問題)裝配線問題(C++)

這幾天一直再看,覺得看懂了一些,先記下來。

1. 動態規劃

動態規劃是運籌學的一個方向,就是把多級最優化問題分解成一系列的單階問題。在不斷增加的過程中,不斷的計算當前問題的最優解。

一般分為如下四個部分:

  • 線性動規:攔截導彈,合唱隊形,挖地雷,建學校,劍客決鬥等;
  • 區域動規:石子合併, 加分二叉樹,統計單詞個數,炮兵佈陣等;
  • 樹形動規:貪吃的九頭龍,二分查詢樹,聚會的歡樂,數字三角形等;
  • 揹包問題:01揹包問題,完全揹包問題,分組揹包問題,二維揹包,裝箱問題,擠牛奶(同濟ACM第1132題)等;

2. 汽車生產線問題

這個問題是《演算法導論》的動態規劃的例題,我自己覺得這道題比較簡單而且典型,所以就解釋下這個題目:

Colonel汽車公司在有兩條裝配線的工廠裡生成汽車。每一條裝配線上有n個裝配站,兩條生產線上相同位置的裝配站功能相同,但所需時間不同,並且汽車底盤在兩條裝配線間轉移要花費一定的時間。如下圖所示兩條生產線。

裝配線圖

  1. 首先我們知道每個階段的最短時間,都包含了上一階段的最短時間。

  2. 而比較簡單的是,我們只有兩種情況,一種是在裝配線1上時間短,一種是在裝配線2上時間短。

  3. 假如暴力搜尋,貪心去算得話(也就是遞迴的辦法)。時間複雜就是2^n,這個是不可接受的。

這個時候我們的辦法是先從第一個問題開始,裝配線1, 2上只有一個station。那麼比較簡單,一比較就好了。當有兩個station的時候,就是從上一次比較的結果中(一個line 1最短,一個line 2最短)中繼續加上當前station的值繼續比較。

所以我們發現是每個當前的最優解,都包含了上一次的最優解。

3. 程式碼

程式碼就是我們從最開始,一直儲存當前問題的最優解,然後去求的下一次的最優解。

//
//  main.cpp
//  DP_line
//
//  Created by Alps on 15/4/26.
//  Copyright (c) 2015年 chen. All rights reserved.
//

#include <iostream>
using namespace std;

#define NUM 5

int main(){
    int first[NUM];//到裝備站1,i的最短路徑長度
    int
second[NUM];//到裝配站2,i的最短路徑長度 int linef[NUM]; //從1進入的路徑 int lines[NUM]; //從2進入的路徑 int a[NUM]; //在裝配站1,i 所需要呆的時間 int b[NUM]; //再裝配站2,i 所需要呆的時間 int m[NUM]; //從裝配站1,i-1 到裝配站2,i的時間 int n[NUM]; //從裝配站2,i-1 到裝配站1,i的時間 int line[NUM]; //當前最短路經所經過的裝配站 int f[NUM]; //當前最短路徑長度 int ea,eb,xa,xb; // ea為進入裝配站1時間,eb為進入2的時間,xa為出裝配站1的時間,xb為出裝配站2的 scanf("%d %d %d %d",&ea,&eb,&xa,&xb); for(int i=0;i<NUM;++i) { scanf("%d %d", &a[i], &b[i]); } first[0] = ea + a[0]; second[0] = eb + b[0]; for(int i=0;i<NUM-1;++i) { scanf("%d %d", &m[i], &n[i]); } for(int i=1;i<NUM;++i) { if(first[i-1] + a[i] < second[i-1] + m[i-1] + a[i]) { first[i] = first[i-1] + a[i]; linef[i] = 1; }else{ first[i] = second[i-1] + m[i-1] + a[i]; linef[i] = 2; } if(second[i-1] + b[i] < first[i-1] + n[i-1] + b[i]) { second[i] = second[i-1] + b[i]; lines[i] = 2; }else { second[i] = first[i-1] + n[i-1] + b[i-1]; lines[i] = 1; } } for(int i=0;i<NUM;++i) { if(first[i] + xa < second[i] + xb) { f[i] = first[i] + xa; line[i] = 1; }else{ f[i] = second[i] + xb; line[i] = 2; } } for(int i=0;i<NUM;++i) { printf("station %d\n",line[i]); } printf("Distince is %d\n",f[NUM-1]); return 0; }

這個程式碼比較簡單,精華就是那個for迴圈了。

測試用例如下:

3 2 3 4
4 3
3 6
6 3
2 3
5 2
2 3
2 4
3 4
4 3

假如有任何建議,歡迎評論。互相學習。謝謝。