hdu1059 Dividing 我的ACM我的梦,回顾篇 完全背包


题目链接在此

        题目大意:就是有价值1、2、3、4、5、6的硬币各多少个,然后让你判断能否把他们分成价值相等的两部分。

        题目思路:目测dp,一看果然dp,完全背包,需要剪枝,硬币个数为容量,下标为value,用一个bool数组就可以标记是否有方案能构成当前下标的money。最后判断数组中下标为sum/2的值是否为为true即可。

        我的代码:

#include <stdio.h>
#include <string.h>
#define MAXN 120005

int main()
{
    int num[7];
    int T = 0;
    while (scanf("%d %d %d %d %d %d", &num[1], &num[2], &num[3], &num[4], &num[5], &num[6]) != EOF)
    {
        T ++;
        if (!(num[1] || num[2] || num[3] || num[4] || num[5] || num[6]))
            break;
        int sum = 0;
        int i, j, k;
        for (i=1; i<=6; i++)
            sum += i * num[i];
        if (sum % 2 != 0)
        {
            printf("Collection #%d:\nCan't be divided.\n\n", T);
            continue;
        }
        int total = sum / 2;
        bool flag[MAXN];
        memset(flag, false, (total+1)*sizeof(flag[0]));
        flag[0] = true;
        for (i=1; i<=num[1]; i++)
            flag[i] = true;
        int much = num[1];
        for (i=2; i<=6; i++)
        {
            if (num[i] == 0)
                continue;
            for (j=much; j>=0; j--)
            {
                if (flag[j])
                {
                    for (k=1; k<=num[i] && j + k * i <= total; k++)
                    {
                        if (flag[j + k * i])
                            break;
                        flag[j + k * i] = true;
                    }
                }
            }
            much += num[i] * i;
        }
        if (flag[total])
        {
            printf("Collection #%d:\nCan be divided.\n\n", T);            
        }
        else
        {
            printf("Collection #%d:\nCan't be divided.\n\n", T);
        }
    }
    return 0;
}

        注意当中if (flag[j + k * i]) break; 这句话,刚开始没加,一直tle,但是仔细想想,就知道了可以如此剪枝,节约非常多的时间,46ms水过。。


你可能感兴趣的:(dp,ACM,完全背包)