EazyChange

导航

 

今天看了一天的动态规划,其他主要还是背包问题了(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;
}

 

posted on 2016-07-18 20:39  EazyChange  阅读(175)  评论(0编辑  收藏  举报