不知道该叫什么,那就砝码称重吧

题目:砝码称重(洛谷P2347)

题目描述

设有1g1g、2g2g、3g3g、5g5g、10g10g、20g20g的砝码各若干枚(其总重\le 10001000),

输入格式

输入方式:a_1 , a_2 ,a_3 , a_4 , a_5 ,a_6a1,a2,a3,a4,a5,a6

(表示1g1g砝码有a_1a1个,2g2g砝码有a_2a2个,…,20g20g砝码有a_6a6个)

输出格式

输出方式:Total=NTotal=N

NN表示用这些砝码能称出的不同重量的个数,但不包括一个砝码也不用的情况)

 

TLE的代码:

#include<cstdio>
#include<algorithm>
using namespace std;
int main()
{
    int f[1005] = {}, c[7] = {0,1,2,3,5,10,20}, sav[1003] = {}, cnt = 0, ans = 0;
    for(int i = 1;i <= 6;i++)
    {
        scanf("%d", &sav[i]);
        cnt += c[i] * sav[i];    
    }
    for(int i = 1;i <= 6;i++)
    {
        for(int j = 0;j <= cnt;j++)
        {
            for(int k = 1;k <= sav[i];k++)
            {
                int add = c[i] * k;
                if(j==0)
                {
                    f[add] = 1;
                }
                else
                {
                    if(f[j] == 1)
                    {
                        f[j+add] = 1;
                    }
                }
            }
        }
    }    
    for(int i = 1;i <= cnt;i++)
    {
        if(f[i] == 1)
        {
            ans++;
        }    
    }
    printf("Total=%d", ans);
    return 0;
}    

正解代码:

#include<cstring>
#include<cstdio>
using namespace std;
int main()
{
    int w[7] = {0,1,2,3,5,10,20}, v[7] = {}, ans = 0, f[1002] = {};
    f[0] = 1;
    for(int i = 1;i <= 6;i++)
    {
        scanf("%d", &v[i]);    
    }
    for(int i = 1;i <= 6;i++)
    {
        for(int j = 1;j <= v[i];j++)//次数 (相当于把每一个砝码看作单独的物体) 
        {
            for(int k = 1000;k >= 0;k--)//防止多次使用 
            {
                if(f[k]) f[k + w[i]] = 1;
            }
        }
    }
    for(int i = 1;i <= 1000;i++)
    {
        if(f[i]) ans++;
    }
    printf("Total=%d", ans);
    return 0;
} 

可以发现:

TLE的代码是先枚举砝码重量,再枚举已得到的砝码的能拼成的重量和,再枚举每次选取的当前种类砝码的个数。

这显然复杂度爆炸(几乎就没有任何优化,基本上用最差的方式枚举每一种组合)

 

而修改后的正解代码先枚举种类,在再用j次当前种类的砝码(注意不是枚举每次选的个数,而是总共选j次),最后再选已经拼出的砝码重量。

这个的复杂的显然更优。

 

由此,我们可以总结出几点规律(在统计种类或方案数的问题中):

为了让时间复杂度更优,要尽量减少枚举物品件数这一步产生的计算(即这一步在多层循环中所在的位置要尽量靠外)。

尽量把同种有限件数的物品看作不同的物品枚举。

 

 

posted @ 2021-05-27 21:01  Mint-hexagram  阅读(69)  评论(0编辑  收藏  举报