Jobdu 1455:珍惜现在,感恩生活 - HDOJ 2191


九度笔记之 1455:珍惜现在,感恩生活 - KingEasternSun的专栏 - 博客频道 - CSDN.NET
为了挽救灾区同胞的生命,心系灾区同胞的你准备自己采购一些粮食支援灾区,现在假设你一共有资金n元,而市场有m种大米,每种大米都是袋装产品,其价格不等,并且只能整袋购买。请问:你用有限的资金最多能采购多少公斤粮食呢?
输入:
输入数据首先包含一个正整数C,表示有C组测试用例,每组测试用例的第一行是两个整数n和m(1<=n<=100, 1<=m<=100),分别表示经费的金额和大米的种类,然后是m行数据,每行包含3个数p,h和c(1<=p<=20,1<=h<=200,1<=c<=20),分别表示每袋的价格、每袋的重量以及对应种类大米的袋数。
输出:
对于每组测试数据,请输出能够购买大米的最多重量,你可以假设经费买不光所有的大米,并且经费你可以不用完。每个实例的输出占一行。
样例输入:
1
8 2
2 100 4
4 100 2
样例输出:
40
https://www.cnblogs.com/tgycoder/p/5329424.html

http://www.cnblogs.com/tanhehe/articles/2998736.html
X. 二进制解法
int main()  
{  
    int nCase,Limit,nKind,i,j,k,  
        v[111],w[111],c[111],dp[111];  
    //v[]存价值,w[]存尺寸,c[]存件数  
    //在本题中,价值是米的重量,尺寸是米的价格  
  
    int count,Value[1111],size[1111];  
    //count存储分解完后的物品总数  
    //Value存储分解完后每件物品的价值  
    //size存储分解完后每件物品的尺寸  
  
    cin>>nCase;  
    while(nCase--)  
    {     
        count=0;  
        cin>>Limit>>nKind;  
        for(i=0;i<nKind;i++)  
        {  
            cin>>w[i]>>v[i]>>c[i];  
              
            //对该种类的c[i]件物品进行二进制分解  
            for(j=1;j<=c[i];j<<=1)  
            {  
                //<<右移1位,相当于乘2  
                Value[count]=j*v[i];  
                size[count++]=j*w[i];  
                c[i] -= j;  
            }  
            if(c[i] > 0)  
            {  
                Value[count]=c[i]*v[i];  
                size[count++]=c[i]*w[i];  
            }  
        }  
  
        //经过上面对每一种物品的分解,  
        //现在Value[]存的就是分解后的物品价值  
        //size[]存的就是分解后的物品尺寸  
        //count就相当于原来的n  
  
        //下面就直接用01背包算法来解  
        memset(dp,0,sizeof(dp));  
  
        for(i=0;i<count;i++)  
            for(j=Limit;j>=size[i];j--)  
                if(dp[j] < dp[j-size[i]] + Value[i])  
                    dp[j]=dp[j-size[i]]+Value[i];  
          
        cout<<dp[Limit]<<endl;  
    }  
    return 0;  
}  

inline void ZeroOnePack(int w,int v)  
{  
    int j;  
    for(j=limit;j>=w;j--)  
    {  
        if(f[j-w]+v > f[j])  
            f[j]=f[j-w]+v;  
    }  
}  
  
inline void CompletePack(int w,int v)  
{  
    int j;  
    for(j=w;j<=limit;j++)  
    {  
        if(f[j-w]+v > f[j])  
            f[j]=f[j-w]+v;  
    }  
}  
  
inline void MultiplePack(int w,int v,int amount)  
{  
    if(amount * w >= limit)  
    {  
        CompletePack(w,v);  
        return ;  
    }  
    for(int k=1;k<amount;k<<=1)  
    {  
        ZeroOnePack(k*w,k*v);  
        amount -= k;  
    }  
    ZeroOnePack(amount*w,amount*v);  
}  
  
int main()  
{  
    int T,n;  
    cin>>T;  
    while(T--)  
    {  
        cin>>limit>>n;  
          
        for(int i=0;i<n;i++)  
            cin>>weight[i]>>Value[i]>>num[i];  
          
        memset(f,0,sizeof(f));  
          
        for(i=0;i<n;i++)  
            MultiplePack(weight[i],Value[i],num[i]);  
          
        cout<<f[limit]<<endl;  
    }  
    return 0;  
}  
第一种方法,把相同的大米单独考虑 在本题中,不同种类的大米含有固定数量的袋数,我们可以把同一种类不同袋的大米单独看作一个物品,比如A类大米有4袋,我们就可以看作4个不同种类的大米,只不过他们的价格,重量是一样的。然后按照背包问题,用动态规划做就行了 。参考题目1209:最小邮票数
  1. void getMax(){  
  2.     int money;  
  3.     int riceClass;  
  4.     std::cin>>money>>riceClass;  
  5.    
  6.     std::vector<int> ricePrice;  
  7.     std::vector<int> riceWeight;  
  8.     int price;  
  9.     int weight;  
  10.     int num;  
  11.     for(int rid = 0;rid<riceClass;rid++){  
  12.         std::cin>>price>>weight>>num;  
  13.         ricePrice.insert(ricePrice.end(),num,price);  
  14.         riceWeight.insert(riceWeight.end(),num,weight); 
  15.     }  
  16.    
  17.     int *dp = new int[money+1];  
  18.     for(int i = 0;i<money+1;i++)  
  19.         dp[i] = 0;  
  20.    
  21.     std::vector<int>::size_type riceNum = ricePrice.size();  
  22.     for(std::vector<int>::size_type rn = 0;rn<riceNum;rn++){  
  23.         for(int m = money; m>=ricePrice.at(rn); m--)  
  24.             dp[m] = max(dp[m], dp[m-ricePrice.at(rn)]+ riceWeight.at(rn));  
  25.     }  
  26.     std::cout<<dp[money]<<std::endl; 
  27. }  
  28. void judo(){  
  29.     int c = 0;  
  30.     while(std::cin>>c){  
  31.         for(int i = 0;i<c;i++)  
  32.         getMax();  
  33.     }  

http://blog.csdn.net/superlc320/article/details/18975493
  1. int main()    
  2. {    
  3.     int C;  
  4.     scanf("%d", &C);  
  5.     while(C--)  
  6.     {  
  7.         Food a[2010];    
  8.         int dp[110];   
  9.         int n, m;  
  10.         while(scanf("%d%d", &n, &m) != EOF)    
  11.         {    
  12.             int i, j, c;    
  13.             for(i = 0; i < m; i++)  
  14.             {  
  15.                 scanf("%d%d%d", &a[i].price, &a[i].weight, &c);  
  16.                 while(--c)  //将多袋粮食分开,将多重背包问题转化为01背包问题  
  17.                 {  
  18.                     i++;  
  19.                     m++;  
  20.                     a[i] = a[i-1];  
  21.                 }  
  22.             }  
  23.             memset(dp, 0, sizeof(int)*110);           //动态规划数组初始化    
  24.             for(i = 0; i < m; i++)                     //动态规划    
  25.                 for(j = n; j >= a[i].price; j--)       //此处必须从大到小    
  26.                     dp[j] = max(dp[j - a[i].price] + a[i].weight , dp[j]);    
  27.             printf("%d\n", dp[n]);    
  28.         }  
  29.     }  
  30.     //system("pause");    
  31.     return 0;    
第二种方法,利用二进制取数优化
       假设某个物品有10个数量,我们取数的方法是先取1个,再取2个,再取4个以此类推(i=1;i<=10;i<<=1);

也就是说,会取到1、2、4个,然后最后还会剩下3个。观察前面3个数,它们任意相加又可以组成3、5、6、7,这些数再与最后深下的3相加又可以得到8、9、10
也就是说,1到10全有了,但是我们操作的次数却从10次降低到了4次!
     关键代码如下,分别选择2^n 个,注意 
1,循环的终止条件为nr<=leftNum            leftNum表示还剩该大米的袋数
2,每次循环 leftNum-=nr     
     该循环的意思就是依次从 riceNum[rid]袋大米中 拿走1,2,……nr 袋大米进行规划,
  1.        int leftNum = riceNum[rid];  
  2.         for(int nr = 1; nr<=leftNum; nr<<1){  
  3.             for(int m = money; m>= nr*ricePrice[rid]; m--)  
  4.                 dp[m] = max(dp[m], dp[m - nr*ricePrice[rid]] + nr*riceWeight[rid]);  
  5.             leftNum-=nr;  
  6.         }  
如果大米还有剩余则,对剩余的大米一袋袋拿走进行规划
  1.       if(leftNum==0){  
  2.             continue;  
  3.         }  
  4.    
  5.         for(int nr = 1; nr<=leftNum; nr<<1){  
  6.             for(int m = money; m>= nr*ricePrice[rid]; m--)  
  7.                 dp[m] = max(dp[m], dp[m - nr*ricePrice[rid]] + nr*riceWeight[rid]);  
  8.         }  
  1. void getMax(){  
  2.     int money;  
  3.     int riceClass;  
  4.     std::cin>>money>>riceClass;  
  5.     int price;  
  6.     int weight;  
  7.     int num;  
  8.     for(int rid = 0;rid<riceClass;rid++){  
  9.         std::cin>>ricePrice[rid]>>riceWeight[rid]>>riceNum[rid];  
  10.     }  
  11.    
  12.     int *dp = new int[money+1];  
  13.     for(int i = 0;i<money+1;i++)  
  14.         dp[i] = 0;  
  15.    
  16.     for(int rid = 0;rid<riceClass;rid++){  
  17.         int leftNum = riceNum[rid];  
  18.         for(int nr = 1; nr<=leftNum; nr<<1){  
  19.             for(int m = money; m>= nr*ricePrice[rid]; m--)  
  20.                 dp[m] = max(dp[m], dp[m - nr*ricePrice[rid]] + nr*riceWeight[rid]);  
  21.             leftNum-=nr;  
  22.         }  
  23.         if(leftNum==0){  
  24.             continue;  
  25.         }  
  26.    
  27.         for(int nr = 1; nr<=leftNum; nr<<1){  
  28.             for(int m = money; m>= nr*ricePrice[rid]; m--)  
  29.                 dp[m] = max(dp[m], dp[m - nr*ricePrice[rid]] + nr*riceWeight[rid]);  
  30.         }  
  31.     }  
  32.    
  33.     std::cout<<dp[money]<<std::endl;  
  34. }  
http://www.cnblogs.com/ka200812/archive/2011/08/06/2129505.html
一个关于多重背包的问题,即给定每个物品的价格和数量,在有限背包中求得可以装进背包的最大价值,一般的做法就是将多重背包转化为诺干个01背包来解决,例如某个物品有1000个,则转化为将这个物品看成1000个只有一个数量的该物品,然后运用01背包,容量反向动规求的解!可是如果某个物品的数量是1W、10W或者是100W,那么岂不是要求上W个01背包了,不超时才怪。
那么有什么好办法可以解决这样的问题呢?从上面的方法中我们看出,我们处理问题的方法是一个一个处理物品,物品有1W个,我们便处理1W次。这样做的好处是编程方便,并且把每个物品都遍历到了,不会有错。可是太慢了。如果我们不是一次取一个,而是一个取很多个,同时我们保证我们取数过程中不会出现丢三落四的情况,那不就爽歪歪了吗?
这里介绍一种办法,用来满足上面的要求。二进制取数!
假设某个物品有10个数量,我们取数的方法是先取1个,再取2个,再取4个以此类推(i=1;i<=10;i<<=1);
也就是说,会取到1、2、4个,然后最后还会剩下3个。观察前面3个数,它们任意相加又可以组成3、5、6、7,这些数再与最后深下的3相加又可以得到8、9、10
也就是说,1到10全有了,但是我们操作的次数却从10次降低到了4次!
for(i=0;i<m;i++) //m种物品
{
    left=num[i]; //每个物品的数量
    for(j=1;j<=left;j<<=1) //二进制取数
    {
        /*do something by yourself*/
        left-=j;
    }
    if(left)  //剩余的数
    {
        /*do something by yourself*/
    }
}
    while(t--)
    {
        cin>>n>>m;
        for(i=0;i<m;i++)
        {
            cin>>p[i]>>w[i]>>b[i];
        }
        memset(f,0,(n+1)*4);
        for(i=0;i<m;i++)
        {
            left=b[i];
            for(j=1;j<=left;j<<=1)
            {
                for(k=n;k>=j*p[i];k--)
                {
                    f[k]=max(f[k],f[k-j*p[i]]+j*w[i]);
                }
                left-=j;
            }
            if(left)
            {
                for(k=n;k>=left*p[i];k--)
                {
                    f[k]=max(f[k],f[k-left*p[i]]+left*w[i]);
                }
            }
        }
        cout<<f[n]<<endl;
    }
http://www.wutianqi.com/?p=537
    while(nCases--)
    {
        memset(nMultiplePack, 0, sizeof(nMultiplePack));
        scanf("%d %d", &nValue, &nKind);
        for(int i=0; i<nKind; ++i)
            scanf("%d %d %d", &value[i], &weight[i], &bag[i]);
        for(int i=0; i<nKind; ++i)
            for(int j=0; j<bag[i]; ++j)
                for(int k=nValue; k>=value[i]; --k)
                    if(nMultiplePack[k] < nMultiplePack[k-value[i]]+weight[i])
                        nMultiplePack[k] = nMultiplePack[k-value[i]] + weight[i];
        printf("%d\n", nMultiplePack[nValue]);
 
    }
http://www.cnblogs.com/easonliu/p/3904161.html
22 void refresh() {
23     for (int i = 0; i < c; ++i) {
24         for (int j = n; j >= p; --j) {
25             if (dp[j-p] >= 0) {
26                 dp[j] = max(dp[j], dp[j-p] + h);
27             }
28             res = max(res, dp[j]);
29         }
30     }
31 }
32  
33 int main() {
34     cin >> C;
35     for (int i = 0; i < C; ++i) {
36         init();
37         cin >> n >> m;
38         for (int j = 0; j < m; ++j) {
39             cin >> p >> h >> c;
40             refresh();
41         }
42         cout << res << endl;
43     }
44     return 0;
45 }
Read full article from 九度笔记之 1455:珍惜现在,感恩生活 - KingEasternSun的专栏 - 博客频道 - CSDN.NET

Labels

LeetCode (1432) GeeksforGeeks (1122) LeetCode - Review (1067) Review (882) Algorithm (668) to-do (609) Classic Algorithm (270) Google Interview (237) Classic Interview (222) Dynamic Programming (220) DP (186) Bit Algorithms (145) POJ (141) Math (137) Tree (132) LeetCode - Phone (129) EPI (122) Cracking Coding Interview (119) DFS (115) Difficult Algorithm (115) Lintcode (115) Different Solutions (110) Smart Algorithm (104) Binary Search (96) BFS (91) HackerRank (90) Binary Tree (86) Hard (79) Two Pointers (78) Stack (76) Company-Facebook (75) BST (72) Graph Algorithm (72) Time Complexity (69) Greedy Algorithm (68) Interval (63) Company - Google (62) Geometry Algorithm (61) Interview Corner (61) LeetCode - Extended (61) Union-Find (60) Trie (58) Advanced Data Structure (56) List (56) Priority Queue (53) Codility (52) ComProGuide (50) LeetCode Hard (50) Matrix (50) Bisection (48) Segment Tree (48) Sliding Window (48) USACO (46) Space Optimization (45) Company-Airbnb (41) Greedy (41) Mathematical Algorithm (41) Tree - Post-Order (41) ACM-ICPC (40) Algorithm Interview (40) Data Structure Design (40) Graph (40) Backtracking (39) Data Structure (39) Jobdu (39) Random (39) Codeforces (38) Knapsack (38) LeetCode - DP (38) Recursive Algorithm (38) String Algorithm (38) TopCoder (38) Sort (37) Introduction to Algorithms (36) Pre-Sort (36) Beauty of Programming (35) Must Known (34) Binary Search Tree (33) Follow Up (33) prismoskills (33) Palindrome (32) Permutation (31) Array (30) Google Code Jam (30) HDU (30) Array O(N) (29) Logic Thinking (29) Monotonic Stack (29) Puzzles (29) Code - Detail (27) Company-Zenefits (27) Microsoft 100 - July (27) Queue (27) Binary Indexed Trees (26) TreeMap (26) to-do-must (26) 1point3acres (25) GeeksQuiz (25) Merge Sort (25) Reverse Thinking (25) hihocoder (25) Company - LinkedIn (24) Hash (24) High Frequency (24) Summary (24) Divide and Conquer (23) Proof (23) Game Theory (22) Topological Sort (22) Lintcode - Review (21) Tree - Modification (21) Algorithm Game (20) CareerCup (20) Company - Twitter (20) DFS + Review (20) DP - Relation (20) Brain Teaser (19) DP - Tree (19) Left and Right Array (19) O(N) (19) Sweep Line (19) UVA (19) DP - Bit Masking (18) LeetCode - Thinking (18) KMP (17) LeetCode - TODO (17) Probabilities (17) Simulation (17) String Search (17) Codercareer (16) Company-Uber (16) Iterator (16) Number (16) O(1) Space (16) Shortest Path (16) itint5 (16) DFS+Cache (15) Dijkstra (15) Euclidean GCD (15) Heap (15) LeetCode - Hard (15) Majority (15) Number Theory (15) Rolling Hash (15) Tree Traversal (15) Brute Force (14) Bucket Sort (14) DP - Knapsack (14) DP - Probability (14) Difficult (14) Fast Power Algorithm (14) Pattern (14) Prefix Sum (14) TreeSet (14) Algorithm Videos (13) Amazon Interview (13) Basic Algorithm (13) Codechef (13) Combination (13) Computational Geometry (13) DP - Digit (13) LCA (13) LeetCode - DFS (13) Linked List (13) Long Increasing Sequence(LIS) (13) Math-Divisible (13) Reservoir Sampling (13) mitbbs (13) Algorithm - How To (12) Company - Microsoft (12) DP - Interval (12) DP - Multiple Relation (12) DP - Relation Optimization (12) LeetCode - Classic (12) Level Order Traversal (12) Prime (12) Pruning (12) Reconstruct Tree (12) Thinking (12) X Sum (12) AOJ (11) Bit Mask (11) Company-Snapchat (11) DP - Space Optimization (11) Dequeue (11) Graph DFS (11) MinMax (11) Miscs (11) Princeton (11) Quick Sort (11) Stack - Tree (11) 尺取法 (11) 挑战程序设计竞赛 (11) Coin Change (10) DFS+Backtracking (10) Facebook Hacker Cup (10) Fast Slow Pointers (10) HackerRank Easy (10) Interval Tree (10) Limited Range (10) Matrix - Traverse (10) Monotone Queue (10) SPOJ (10) Starting Point (10) States (10) Stock (10) Theory (10) Tutorialhorizon (10) Kadane - Extended (9) Mathblog (9) Max-Min Flow (9) Maze (9) Median (9) O(32N) (9) Quick Select (9) Stack Overflow (9) System Design (9) Tree - Conversion (9) Use XOR (9) Book Notes (8) Company-Amazon (8) DFS+BFS (8) DP - States (8) Expression (8) Longest Common Subsequence(LCS) (8) One Pass (8) Quadtrees (8) Traversal Once (8) Trie - Suffix (8) 穷竭搜索 (8) Algorithm Problem List (7) All Sub (7) Catalan Number (7) Cycle (7) DP - Cases (7) Facebook Interview (7) Fibonacci Numbers (7) Flood fill (7) Game Nim (7) Graph BFS (7) HackerRank Difficult (7) Hackerearth (7) Inversion (7) Kadane’s Algorithm (7) Manacher (7) Morris Traversal (7) Multiple Data Structures (7) Normalized Key (7) O(XN) (7) Radix Sort (7) Recursion (7) Sampling (7) Suffix Array (7) Tech-Queries (7) Tree - Serialization (7) Tree DP (7) Trie - Bit (7) 蓝桥杯 (7) Algorithm - Brain Teaser (6) BFS - Priority Queue (6) BFS - Unusual (6) Classic Data Structure Impl (6) DP - 2D (6) DP - Monotone Queue (6) DP - Unusual (6) DP-Space Optimization (6) Dutch Flag (6) How To (6) Interviewstreet (6) Knapsack - MultiplePack (6) Local MinMax (6) MST (6) Minimum Spanning Tree (6) Number - Reach (6) Parentheses (6) Pre-Sum (6) Probability (6) Programming Pearls (6) Rabin-Karp (6) Reverse (6) Scan from right (6) Schedule (6) Stream (6) Subset Sum (6) TSP (6) Xpost (6) n00tc0d3r (6) reddit (6) AI (5) Abbreviation (5) Anagram (5) Art Of Programming-July (5) Assumption (5) Bellman Ford (5) Big Data (5) Code - Solid (5) Code Kata (5) Codility-lessons (5) Coding (5) Company - WMware (5) Convex Hull (5) Crazyforcode (5) DFS - Multiple (5) DFS+DP (5) DP - Multi-Dimension (5) DP-Multiple Relation (5) Eulerian Cycle (5) Graph - Unusual (5) Graph Cycle (5) Hash Strategy (5) Immutability (5) Java (5) LogN (5) Manhattan Distance (5) Matrix Chain Multiplication (5) N Queens (5) Pre-Sort: Index (5) Quick Partition (5) Quora (5) Randomized Algorithms (5) Resources (5) Robot (5) SPFA(Shortest Path Faster Algorithm) (5) Shuffle (5) Sieve of Eratosthenes (5) Strongly Connected Components (5) Subarray Sum (5) Sudoku (5) Suffix Tree (5) Swap (5) Threaded (5) Tree - Creation (5) Warshall Floyd (5) Word Search (5) jiuzhang (5)

Popular Posts