POJ-1742-Coins-優化的多重揹包
阿新 • • 發佈:2018-11-19
題目傳送門
題意:
有n種硬幣,這n種硬幣的價值為coin[i].val,第i種硬幣的個數為coin[i].num個,問能用這些硬幣支付多少不超過m的價格?
思路:
多重揹包裸題,但是要進行空間和時間上的優化,否則會MLE和TLE。
空間優化:通過特定的順序滾動陣列,來降維。具體可以參考揹包九講
時間優化:一般的多重揹包有3重迴圈,i,j,k-種類,價值,數量。這裡優化掉數量那一重迴圈。具體細節看程式碼註釋。
AC code: #include<iostream> #include<cstdio> #include<algorithm> #include<vector> #include<set> #include<stack> #include<queue> #include<map> #include<cstring> #include<string> #include<cmath> using namespace std; typedef long long LL; #define INF 0x3f3f3f3f #define PI acos(-1.0) #define pii pair<int,int> #define all(x) x.begin(),x.end() #define mem(a,b) memset(a,b,sizeof(a)) #define per(i,a,b) for(int i = a;i <= b;++i) #define rep(i,a,b) for(int i = a;i >= b;--i) const int maxn = 1e5; int n = 0,m = 0; struct node{ int val,num; }; node coin[maxn+10]; bool dp[maxn+10];//不能用二維陣列,那樣會MLE,要滾動降維 int cnt[maxn+10]; bool cmp(node a,node b){ return a.val != b.val ? a.val < b.val : a.num < b.num; } void solve(){ fill(dp,dp+(maxn+10),false); dp[0] = true; per(i,1,n){ fill(cnt,cnt+maxn+10,0); per(j,0,m){//正序,因為是從更新後的狀態退出後面的j的狀態的 if(dp[j] == true){//不要跳過,否則cnt會+1,導致過快選擇的i種卡超過數量限制 continue;//為了保證使用最少的第i種卡,湊出j } if(j >= coin[i].val && dp[j-coin[i].val] && cnt[j - coin[i].val] < coin[i].num){ dp[j] = dp[j - coin[i].val]; cnt[j] = cnt[j-coin[i].val] + 1; } } } int ans = 0; per(i,1,m){ ans += dp[i] ? 1 : 0; } printf("%d\n",ans); } int main(){ while(~scanf("%d %d",&n,&m) && ( m +n )){ per(i,1,n){ scanf("%d",&coin[i].val); } per(i,1,n){ scanf("%d",&coin[i].num); } //sort(coin+1,coin+1+n,cmp);//排序是多餘的 solve(); } return 0; }