Talk is cheap, show me the code.
一、問題描述
現有一組砝碼,重量互不相等,分別爲m1,m2,m3…mn;
每種砝碼對應的數量爲x1,x2,x3…xn。現在要用這些砝碼去稱物體的重量,問能稱出多少中不同的重量。
注:
稱重重量包括0
方法原型:public static int fama(int n, int[] weight, int[] nums)
輸入描述:
輸入包含多組測試數據。
對於每組測試數據:
第一行:n — 砝碼數(範圍[1,10])
第二行:m1 m2 m3 … mn — 每個砝碼的重量(範圍[1,2000])
第三行:x1 x2 x3 …. xn — 每個砝碼的數量(範圍[1,6])
輸出描述:
利用給定的砝碼可以稱出的不同的重量數
輸入例子:
2
1 2
2 1
輸出例子:
5
二、問題分析
這道題要求思路比較開闊,初拿到題目,可能習慣性地就按組合問題的思路來思考,先從所有砝碼中選一個砝碼,記錄不同重量在set中,然後再考慮從所有砝碼中選兩個砝碼的情況,這相當於又是從頭開始選砝碼,選兩個砝碼複雜度是 O(n*n),把不存在set中的重量加入到set中,然後再考慮從所有砝碼中選三個砝碼的情況,複雜度是 O(n * n * n)…可見這種思路是思考問題的常規思路,但是解法的複雜度太高,幾乎不可能完成。所有組合問題都有這個特點,按這種思路思考下去一定是無法求解問題的。另外一種常規思路是,先考慮所有砝碼組成的最大重量,然後從 0 一直考慮到最大重量,看能不能從現有砝碼中組成相應重量,但是這也是涉及選砝碼的工作,複雜度也是非常高,所以也是不可行的。那麼,這兩種常規思路的高複雜度來源於每次選砝碼的工作都是從頭做起,那麼就需要考慮動態規劃的算法,即每次選砝碼都是基於上一次的選擇結果。
這種動態規劃的算法也有多種思路。思路一,可以先從所有不同重量的砝碼中考慮選擇一個砝碼出來,記錄所有可能的重量,然後在從所有不同重量的砝碼中選擇一個砝碼出來,在已有重量記錄中分別加上第二次選出來的砝碼的重量,不存在的話就將重量加入記錄,但是這種思路的缺點是第二次選擇砝碼有多種可能性,程序不好處理。那麼只剩下一種考慮方向了,就是 n 種不同重量砝碼一種接一種地考慮,先考慮第一種重量的砝碼,記錄第一種砝碼不同個數所有可能組成的重量,然後再考慮第二種重量的砝碼,第二種重量的砝碼加入需要考慮兩種情況,一種情況是它自身不同個數所有可能組成的重量,如果不存在已有記錄則加入記錄,另一種情況是第二種重量砝碼不同個數分別加在已有記錄中各個重量上,如果新產生的重量不存在於記錄中則加入記錄。
#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;
int main()
{
int n;
while (cin >> n)
{
vector<int> mvect, xvect;
int m, x;
int temp = n;
while (temp--)
{
cin >> m;
mvect.push_back(m);
}
temp = n;
while (temp--)
{
cin >> x;
xvect.push_back(x);
}
vector<int> vect;
for (int i = 0; i < n; i++)
{
int size = vect.size();
for (int k = 0; k < size; k++)
{
for (int j = 1; j <= xvect[i]; j++)
{
temp = vect[k] + j * mvect[i];
if (find(vect.begin(), vect.end(), temp) == vect.end())
{
vect.push_back(temp);
}
}
}
for (int j = 1; j <= xvect[i]; j++)
{
temp = j * mvect[i];
if (find(vect.begin(), vect.end(), temp) == vect.end())
{
vect.push_back(temp);
}
}
}
cout << 1 + vect.size() << endl;
}
return 0;
}