1. 程式人生 > >鋼鐵切割問題 動態規劃(輸出切割方案和帶成本的解法)

鋼鐵切割問題 動態規劃(輸出切割方案和帶成本的解法)

  

問題描述:

假定我們知道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英寸的鋼條切割,首先切一刀會切成兩部分,或者不切。現在就比較這兩種情況哪種的收益高(切或者不切),如果不切收益高,那麼結果直接就是不切的收益,如果切成兩部分,那麼這兩部分又可以看成是有兩個不同長度的鋼條,每一個鋼條接著按這個方法討論。這種方法其實就是動態規劃的自底向上法。這種方法一般需要且當定義子問題“規模”的概念,是的任何子問題的求解都只依賴於“更小的”自問題的求解。因而我們可以將子問題按規模排序,按由小到大的順序進行求解。當求某個子問題時,它所依賴的哪些更小的子問題都已經求解完畢,結果已經儲存。每個子問題鬥智求解一次,當我們求解它時,它的所有前提子問題都以求解完成。下面先給出這個題的程式碼,然後再做詳細解釋:

#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;
}

  主函式的一些輸入輸出只是一個形式就不詳細說了,重點說一下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不滿足條件了,所以結果輸出程式結束。

最後附上演算法導論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;
}