一名苦逼的OIer,想成为ACMer

Iowa_Battleship

洛谷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;
}

posted on 2018-10-19 16:52  Iowa_Battleship  阅读(130)  评论(0编辑  收藏  举报

导航