HDU 1059 (DP)

题意是有价值1-6的大理石,告诉你每种价值的个数问能不能分成总价值相同的两堆。

首先每种石头需要计算的个数不会超过6个。

比如对于1,如果最后分成的两堆都有1,那么我们可以预先把相同数量的1拿掉,最后使得只剩下某一堆中含有1,那么最多含有多少呢?应该是5。因为如果有大于等于6的1,那么我们总可以在另一堆中拿掉一块大理石,那后这一堆中拿掉相应数量的1补偿。所以1最多只有5块。

比如对于2,同样的我们假设只有一堆里面有2,那么最多有多少数量呢?如果另一堆里面有4或者6,那么我们总可以拿掉一个6或者4,然后在这一堆拿掉等价的2,也就是另一堆有4或者6的话这一堆最多只能有1个2。同样的另一堆有3和5同时存在的话,这一堆2最多只有3个。

经过这些分析发现其实每一堆的石头其实有很多都是没用的,所以我们可以模掉一个数。然后可以用最基本的DP解决了。

#include <bits/stdc++.h>
using namespace std;
#define maxn 121111

bool dp[maxn];
int a[maxn], tot;

int main () {
    //freopen ("in", "r", stdin);
    int kase = 0;
    while (1) {
        bool ok = 0;
        tot = 0;
        for (int i = 1; i <= 6; i++) {
            int num;
            scanf ("%d", &num);
            if (num != 0)
                ok = 1;
            if (num > 6) {
                num %= 6;
                if (num == 0)
                    num = 6;
            }
            for (int j = 0; j < num; j++)
                a[++tot] = i;
        }
        if (!ok)
            break;
        memset (dp, 0, sizeof dp);
        dp[0] = 1;
        int sum = 0;
        for (int i = 1; i < tot; i++) {
            for (int j = sum; j >= 0; j--) {
                if (dp[j])
                    dp[j+a[i]] = 1;
            }
            sum += a[i];
        }
        sum = 0;
        for (int i = 1; i <= tot; i++)
            sum += a[i];
        printf ("Collection #%d:\n", ++kase);
        if ((sum&1) || dp[sum>>1] == 0)
            printf ("Can't be divided.\n");
        else printf ("Can be divided.\n");
        printf ("\n");
    }
     return 0;
}


你可能感兴趣的:(HDU 1059 (DP))