zoukankan      html  css  js  c++  java
  • 全是套路——背包问题(还有待检验)

    今天看了一天的动态规划,其他主要还是背包问题了(01背包,完全背包,多重背包)

    核心就是状态转移方程了,在说下几个重要的问题:

    1.01背包开始为什么是从V到0?

    因为要比较f[i-1][j]和f[i-1][j-w[i]]+v[i].如果从0到v,则j-w[i]是先算的,所以f[j]就是根据f[j-w[i]]算出来的。也就是说,要注意因果关系。

    2.如果多重背包和完全背包转换成01背包,则也需要从v-0循环

    3.完全背包和多重背包相似,但是区别于01背包。01背包考虑的是放于不放,而完全背包和多重背包考虑的是放0,1,2……个(或者有限个)。

    所以完全背包和多重背包,需要写一个求序列最大值的函数。而最后是把那个最大值赋给f[i][j].

    根据以上分析,总结一下背包问题要做的事:

    1.分析状态转移方程,这个很基本。

    2.把f[i][j]这个数组全部初始化为0.

    3.要把f[0][c]这个一行给初始化了,值都是从V-0的值。

    4.开始根据状态转移方程来写循环。

    以下是我写的完全背包例程:

    #include <stdio.h>
    #include <iostream>
    #include <stack>
    #include <string>
    #include <vector>
    #include <list>
    #include <algorithm>
    #include <deque>
    
    using namespace std;
    
    
    int a[10][100];
    int n = 0, c = 0;
    
    int max(int a, int b)
    {
        return a >= b ? a : b;
    }
    
    int max_data(vector<int> m)
    {
        int max = 0;
        for (int i = 0; i < m.size(); i++)
        {
            if (m[i] >= max)
            {
                max = m[i];
            }
        }
        return max;
    }
    
    void fun(vector<int> w, vector<int> v, vector<int> num)
    {
        for (int j = c; j >= 0; j--)
        {
            for (int k = 0; k <= c/w[0]; k++)
            {
                if (j >= k*w[0])
                {
                    a[0][j] = k*v[0];
                }
            }
        }
        for (int i = 1; i < n; i++)
        {
            for (int j = c; j >= 0; j--)
            {
                vector<int> tmp;
                for (int k = 0; k <= c/w[i]; k++)
                {
                    if (j >= k*w[i])
                    {
                        tmp.push_back(a[i - 1][j - k*w[i]] + k*v[i]);
                    }
                }
                a[i][j] = max_data(tmp);
            }
        }
    }
    
    
    
    int main()
    {
        
        while (cin >> c>>n)
        {
            vector<int> w, v, num;
            for (int i = 0; i < n; i++)
            {
                int tmp1, tmp2, tmp3;
                cin >> tmp1 >> tmp2 >> tmp3;
                w.push_back(tmp1);
                v.push_back(tmp2);
                num.push_back(tmp3);
            }
            fun(w, v, num);
            cout << a[n-1][c] << endl;
        }
    
        return 0;
    }

    最后再结合今天做的称砝码问题:

    有一组砝码,重量互不相等,分别为m1m2m3……mn;它们可取的最大数量分别为x1x2x3……xn 
    现要用这些砝码去称物体的重量,问能称出多少种不同的重量。 
    Input
    测试数据第一行一个整数nn<=10),表示有多种不同的砝码; 
    第二行n个整数(中间用空格分隔),m1m2m3……mn,分别表示n个砝码的重量;(1<=mi<=20 
    第三行n个整数(中间用空格分隔),x1x2x3……xn,分别表示n个砝码可取的最大数量。(1<=xi<=20 
    Output
    每组数据输出仅一行,一个整数,表示利用给定的砝码可以称出的不同的重量数。 
    注:包括0 
    Sample Input
    2

    1 2

    2 1

    其实这个问题,就是背包问题。

    总的砝码质量c我们是可以知道的,题目就变成了,有一个可以装下总质量c砝码的背包。

    现在有n组砝码w[i],每组有num[i]个,可以放可以不放。这就是多重背包。

    我们在动态规划的过程中,会把所有的可能都列出来。

    最后再对列出的所有结果去重就可以了。

    #include <stdio.h>
    #include <iostream>
    #include <stack>
    #include <string>
    #include <vector>
    #include <list>
    #include <algorithm>
    #include <deque>
    
    using namespace std;
    
    
    int a[100][100];
    int n = 0, c = 0;
    
    int max(int a, int b)
    {
        return a >= b ? a : b;
    }
    
    int max_data(vector<int> m)
    {
        int max = 0;
        for (int i = 0; i < m.size(); i++)
        {
            if (m[i] >= max)
            {
                max = m[i];
            }
        }
        return max;
    }
    
    void fun(vector<int> w,vector<int> num)
    {
        for (int j = c; j >= 0; j--)
        {
            for (int k = 0; k <= num[0]; k++)
            {
                if (j >= k*w[0])
                {
                    a[0][j] = k*w[0];
                }
            }
        }
        for (int i = 1; i < n; i++)
        {
            for (int j = c; j >= 0; j--)
            {
                vector<int> tmp;
                for (int k = 0; k <= num[i]; k++)
                {
                    if (j >= k*w[i])
                    {
                        tmp.push_back(a[i - 1][j - k*w[i]] + k*w[i]);
                    }
                }
                a[i][j] = max_data(tmp);
            }
        }
    }
    
    
    
    int main()
    {
        
        while (cin >>n)
        {
            vector<int> w,num;
            for (int i = 0; i < n; i++)
            {
                int tmp1;
                cin >> tmp1;
                w.push_back(tmp1);
            }
            for (int i = 0; i < n; i++)
            {
                int tmp1;
                cin >> tmp1;
                num.push_back(tmp1);
            }
            for (int i = 0; i < n; i++)
            {
                c += w[i] * num[i];
            }
    
            fun(w,num);
            vector<int> res;
            for (int i = 0; i < 100; i++)
            {
                for (int j = 0; j < 100; j++)
                {
                    res.push_back(a[i][j]);
                }
            }
            sort(res.begin(), res.end());
            res.erase(unique(res.begin(), res.end()), res.end());
            cout << res.size() << endl;
        }
    
        return 0;
    }
  • 相关阅读:
    [zz] 从VMM中终止GUEST OS中运行进程
    [zz]Linux流量监控工具 – iftop (最全面的iftop教程)
    [zz]Ubuntu终端下Nethogs网络流量监控工具
    AtomicBoolean运用
    JDK中的URLConnection参数详解
    java读取文本文件数据
    tomcat时区设置
    java的upload
    java复习(set 、list、map)
    NIO学习笔记1
  • 原文地址:https://www.cnblogs.com/wyc199288/p/5682581.html
Copyright © 2011-2022 走看看