動態規劃(DP問題)裝配線問題(C++)
阿新 • • 發佈:2019-01-03
這幾天一直再看,覺得看懂了一些,先記下來。
1. 動態規劃
動態規劃是運籌學的一個方向,就是把多級最優化問題分解成一系列的單階問題。在不斷增加的過程中,不斷的計算當前問題的最優解。
一般分為如下四個部分:
- 線性動規:攔截導彈,合唱隊形,挖地雷,建學校,劍客決鬥等;
- 區域動規:石子合併, 加分二叉樹,統計單詞個數,炮兵佈陣等;
- 樹形動規:貪吃的九頭龍,二分查詢樹,聚會的歡樂,數字三角形等;
- 揹包問題:01揹包問題,完全揹包問題,分組揹包問題,二維揹包,裝箱問題,擠牛奶(同濟ACM第1132題)等;
2. 汽車生產線問題
這個問題是《演算法導論》的動態規劃的例題,我自己覺得這道題比較簡單而且典型,所以就解釋下這個題目:
Colonel汽車公司在有兩條裝配線的工廠裡生成汽車。每一條裝配線上有n個裝配站,兩條生產線上相同位置的裝配站功能相同,但所需時間不同,並且汽車底盤在兩條裝配線間轉移要花費一定的時間。如下圖所示兩條生產線。
首先我們知道每個階段的最短時間,都包含了上一階段的最短時間。
而比較簡單的是,我們只有兩種情況,一種是在裝配線1上時間短,一種是在裝配線2上時間短。
假如暴力搜尋,貪心去算得話(也就是遞迴的辦法)。時間複雜就是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
假如有任何建議,歡迎評論。互相學習。謝謝。