挑戰 多重部分和問題
阿新 • • 發佈:2019-01-21
挑戰程式設計P62 多重部分和問題
題意:有n種不同大小的數字,每種數字各mi個。判斷是否可以衝這些數字中選出若干個使他們的和加起來等於K、
有兩種dp方法,但是時間複雜度不一樣
第一種:定義dp[i][j]:是否前i種數字能相加等於j,
則dp[i][j]=dp[i][j]|dp[i-1][j-t*a[i]] (0<=t<=m[i])
但是這種定義的複雜度為O(n*K*m),太大了
所以第二種(這種不太容易想到):
定義dp[i][j]:用前i種數字組成j時m[i]的最多剩餘個數
if dp[i-1][j]>=0 dp[i][j]=m[i] 這句很關鍵,而且需要首先判斷
if dp[i][j-a[i]]<=0或j<a[i] dp[i][j]=-1;
else dp[i][j]=dp[i][j-a[i]]-1;
這樣複雜度降為O(N*K)
其中,二維還可以降為一維,因為只需要利用dp[i-1][j],dp[i]而已
//多重部分和問題 #include<stdio.h> #include<string.h> #include <iostream> using namespace std; const int maxn=10010; int dp[100][maxn],a[maxn],m[maxn],n,k; //dp[i][j]表示前i種數加和得到j時第i種數最多能剩餘多少個 void solve() { memset(dp,-1,sizeof(dp)); dp[0][0]=0; for(int i=1;i<=n;i++) { for(int j=0;j<=k;j++) { //注意這裡的順序,如果把else if 提到前面則輸出錯誤 //可以使用一維陣列 if(dp[i-1][j]>=0) dp[i][j]=m[i]; else if(j<a[i]||dp[i][j-a[i]]<=0) dp[i][j]=-1; else dp[i][j]=dp[i][j-a[i]]-1; } } for(int i=0;i<=n;i++) { for(int j=0;j<=k;j++) cout<<dp[i][j]<<" "; cout<<endl; } cout<<(dp[n][k]>=0?"Yes":"No")<<endl; } int main() { cin>>n>>k; for(int i=1;i<=n;i++) cin>>a[i]>>m[i]; solve(); return 0; }