1. 程式人生 > >洛谷1441 砝碼稱重

洛谷1441 砝碼稱重

原題連結

挺水的一道題。
\(DFS\)列舉被刪除的砝碼,每次刪完後進行\(01\)揹包計數,取最大值即可。
這題不需要剪枝即可通過。
我這裡是用連結串列儲存的資料。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 25;
const int M = 2010;
struct dd {
    int x, pre, suc;
};
dd a[N];
int f[M], n, m, ma, s;
inline int re()
{
    int x = 0;
    char c = getchar();
    bool p = 0;
    for (; c < '0' || c > '9'; c = getchar())
        p |= c == '-';
    for (; c >= '0' && c <= '9'; c = getchar())
        x = x * 10 + c - '0';
    return p ? -x : x;
}
inline int maxn(int x, int y)
{
    return x > y ? x : y;
}
bool comp(dd x, dd y)
{
    return x.x < y.x;
}
void de(int x)
{
    a[a[x].pre].suc = a[x].suc;
    a[a[x].suc].pre = a[x].pre;
}
void con(int x)
{
    a[a[x].pre].suc = x;
    a[a[x].suc].pre = x;
}
int calc()
{
    int i, j, k = 0;
    memset(f, 0, sizeof(f));
    f[0] = 1;
    for (i = a[0].suc; i <= n; i = a[i].suc)
        for (j = s; j >= a[i].x; j--)
            if (!f[j] && f[j - a[i].x])
            {
                f[j] |= f[j - a[i].x];
                k++;
            }
    return k;
}
void dfs(int x, int nw)
{
    if (!(nw ^ m))
    {
        ma = maxn(ma, calc());
        return;
    }
    if (x > n)
        return;
    dfs(x + 1, nw);
    de(x);
    s -= a[x].x;
    dfs(x + 1, nw + 1);
    s += a[x].x;
    con(x);
}
int main()
{
    int i;
    n = re();
    m = re();
    for (i = 1; i <= n; i++)
        a[i].x = re();
    sort(a + 1, a + n + 1, comp);
    for (i = 1, a[0].suc = 1, a[n + 1].pre = n; i <= n; i++)
    {
        a[i].pre = i - 1;
        a[i].suc = i + 1;
        s += a[i].x;
    }
    dfs(1, 0);
    printf("%d", ma);
    return 0;
}