1. 程式人生 > >動態規劃解決N個數之和為K

動態規劃解決N個數之和為K

問題:給定一個整數K和n個不同大小的商品,第i個物品的大小整數位ki ,尋找一個物品的子集,它們的和正好為為K ,或者確定不存在這樣的子集

用動態規劃解決問題的時候,求出問題的一個解,而不是所有的解。如果求出所有的解,我目前想到的用回溯法解決,不過要指數之間的複雜度

P(N,K)可以通過判斷P(N-1,K)和P(N-1,K-kn)的解來判斷,如果這兩個子集都無解,則問題沒有解。我們不僅要知道P(N,K)中有解的情況,還要知道所有數值a<=K的是否有解

一般的話P(i,j)表示前i物體,大小為j,是否有解

歸納假設:已知如何求解P(n-1,k),其中0<=k<=K

那麼P(n,K) 可以通過判斷 P(n-1,K) 和P(n-1,K-kn) 來判斷。

如果還想知道有解的時候,含有哪些元素 ,要做個標記belong 

程式碼如下

// 揹包問題(n個整數和問題).cpp : 定義控制檯應用程式的入口點。
//

#include "stdafx.h"
#include <iostream>
using namespace std;
#define N 5
#define K 10
typedef struct
{
	bool exit;
	bool belong;
}NODE ;

int _tmain(int argc, _TCHAR* argv[])
{
	int i,j;
	int arr[N+1];
	cout<<"input the number"<<endl;
	for(i=1;i<=N;i++)
	{
		cin>>arr[i];
	}
	//NODE (*P)[K+1]=new NODE (*)[K+1];
	NODE **P=new NODE *[K+1];
	for(i=0;i<=N;i++)
	{
		P[i]=new NODE[K+1]();
	}

	//元素從1---->N 
	
	for(i=0;i<=K;i++)
	{
		P[0][i].exit=false;
		P[0][i].belong=false;
	}
	P[0][0].exit=true;
	for(i=1;i<=N;i++)
		for(j=0;j<=K;j++)
		{
			if(P[i-1][j].exit)
			{
				P[i][j].exit=true;
				P[i][j].belong=false;
			}else if(j>=arr[i])
			{
				if(P[i-1][j-arr[i]].exit)
				{
					P[i][j].exit=true;
					P[i][j].belong=true;
				}
			}
			
		}

		if(P[N][K].exit==false )
		{
			cout<<"sorry not exit"<<endl;
		}
		else
		{
			int res=K;//剩餘的
			for(i=N;i>=1;i--)
			{
				if(P[i][res].exit&&P[i][res].belong)
				{
					cout<<arr[i]<<"  ";
					res=res-arr[i];
				}

			}
		}
	
	return 0;
}

時間複雜度 O(N*K).


這個演算法有缺點:K不能是實數,K太大的話,空間呢複雜度太高。

如果哪位大神,想到對於K為實數,或者有更好的方法,請不吝賜教。