鋼鐵切割問題 動態規劃(輸出切割方案和帶成本的解法)
阿新 • • 發佈:2019-01-01
問題描述:
假定我們知道sering公司出售一段長度為I英寸的鋼條的價格為pi(i=1,2,3….)鋼條長度為整英寸如圖給出價格表的描述
長度i |
1 |
2 |
4 |
5 |
6 |
7 |
8 |
9 |
價格p[i] |
1 |
5 |
9 |
10 |
17 |
17 |
20 |
24 |
這個題不說什麼遞迴演算法複雜度有多高的什麼的問題了,就直接說一下動態規劃,首先我們這樣想這個題,就是把長度為i英寸的鋼條切割,首先切一刀會切成兩部分,或者不切。現在就比較這兩種情況哪種的收益高(切或者不切),如果不切收益高,那麼結果直接就是不切的收益,如果切成兩部分,那麼這兩部分又可以看成是有兩個不同長度的鋼條,每一個鋼條接著按這個方法討論。這種方法其實就是動態規劃的自底向上法。這種方法一般需要且當定義子問題“規模”的概念,是的任何子問題的求解都只依賴於“更小的”自問題的求解。因而我們可以將子問題按規模排序,按由小到大的順序進行求解。當求某個子問題時,它所依賴的哪些更小的子問題都已經求解完畢,結果已經儲存。每個子問題鬥智求解一次,當我們求解它時,它的所有前提子問題都以求解完成。下面先給出這個題的程式碼,然後再做詳細解釋:
主函式的一些輸入輸出只是一個形式就不詳細說了,重點說一下int bottom_up_cut_rod(int p[],int n)這個函式,這個函式有兩個引數,一個是價格表p和鋼條長度,然後這個函式就是把每一個長度都從i 到n都作出一個最優收益值,就如j從1開始,列出最優收益值放在陣列r【】中,然後如果j等於7需要分割的時候會自動讀取出前面的最優收益值。然後把最大收益值的切割的第一段鋼條長度儲存在在另一個數組s[]中,函式print_cut(int p[],int n,int s[])的實現就是總長度減去第一段鋼條長度,然後接著判斷剩下的長度是否滿足條件,最後將切割方案輸出.在這舉個例子,如果輸入的n是7的話,首先從1到7算出了其對應的最優切割方案,然後將切割方案輸出的時候,首先會輸出s[7],這個時候s[7]=1,首先會把1打印出來,接著n=n-s[7]=6,滿足n>0。然後打印出s[6],這個時候s[6]=6(因為6的最優切割方案就是不切割),此時n=0不滿足條件了,所以結果輸出程式結束。#include<iostream> #include<cstdio> #include<algorithm> #define inf 0x3f3f3f3f using namespace std; int p[10010]; int r[10010]; int s[10010]; int n; int bottom_up_cut_rod(int p[],int n) { for(int i=0;i<=n;i++) r[i]=0; int q; for(int j=1;j<=n;j++) { q=-inf; for(int i=1;i<=j;i++) { if(q<p[i]+r[j-i]) { q=p[i]+r[j-i]; s[j]=i; } } r[j]=q; } return r[n]; } int print_cut(int p[],int n,int s[]) { while(n>0) { printf("%d ",s[n]); n=n-s[n]; } cout<<endl; } int main() { int num; cout<<"請輸入鋼條收益"<<endl; cin>>num; for(int i=1;i<=num;i++) scanf("%d",&p[i]); cout<<"請輸入鋼條長度:\n"<<endl; while(~scanf("%d",&n)) { cout<<"最大收益是:"<<bottom_up_cut_rod(p,n)<<endl; cout<<"切割方案為: "; print_cut(p,n,s); cout<<endl; cout<<"請輸入鋼條長度:\n"<<endl; } return 0; }
最後附上演算法導論15.1-3加固定成本的問題解:
#include<iostream>
#include<cstdio>
#include<algorithm>
#define inf 0x3f3f3f3f
using namespace std;
int p[10010];
int r[10010];
int s[10010];
int n;
int bottom_up_cut_rod(int p[],int n,int c)
{
for(int i=0;i<=n;i++) r[i]=0;
int q;
for(int j=1;j<=n;j++)
{
q=-inf;
for(int i=1;i<=j;i++)
{
if(q<(p[i]+r[j-i]-c*(j!=i)))
{
q=(p[i]+r[j-i]-c*(j!=i));
s[j]=i;
}
}
r[j]=q;
}
return r[n];
}
int print_cut(int p[],int n,int s[])
{
while(n>0)
{
printf("%d ",s[n]);
n=n-s[n];
}
cout<<endl;
}
int main()
{
int num,c;
cout<<"請輸入鋼條收益"<<endl;
cin>>num;
for(int i=1;i<=num;i++) scanf("%d",&p[i]);
cin>>c;
cout<<"請輸入鋼條長度:\n"<<endl;
while(~scanf("%d",&n))
{
cout<<"最大收益是:"<<bottom_up_cut_rod(p,n,c)<<endl;
cout<<"切割方案為: ";
print_cut(p,n,s);
cout<<endl;
cout<<"請輸入鋼條長度:\n"<<endl;
}
return 0;
}