贪心(5)泛背包问题

目录

一,泛背包问题

二,OJ实战

CSU 1775: 悲催的移寝

CSU 1926: 使用最少的硬币

CodeForces 538B Quasi Binary


一,泛背包问题

这一类贪心问题里面有点类似背包问题,但并不是真正的背包问题。

真正的背包问题,基本上都是统筹规划类的问题。

二,OJ实战

CSU 1775: 悲催的移寝

题目:

Description

对于csuxushu来说,能够在CSU(California State University)上学是他一生的荣幸,而换校区搬寝室则是他最大的不幸。顺利通过省赛选拔,开心的csuxushu现在需要着手准备搬家事宜。
对于好学的csuxushu来说,唯一头疼的就是书籍的搬运了,因为他的书实在是太多了。为了防止书籍在运输过程中受损,他打算定制特制的储物保护箱。为了简单起见,我们假设他所有的书都是一样规格。由于是批量定制,这些储物箱都有相同的长度L,宽度和厚度都是一本书的宽度和厚度。csuxushu有一个特殊的要求,那就是每个储物箱最多只能放两本书。当然,他需要运走所有的N本书,并且每一个储物箱里书的总长度不能超过L。
尽管校队队员给了csuxushu许多奖励,csuxushu还是想定尽可能少的储物箱,以求节约经费,然而面对这么困难的问题他显然是一脸懵逼,这时候他想到了你——全CSU最厉害的程序员来帮助他解决这个问题。

Input

第一行一个整数T,代表有T组数据,之后一个空行并且接下来每两组数据之间有一个空行。
每组数据第一行,为1个整数n (1 ≤ n ≤ 10^5),代表有n本书。第二行,为1个整数L ,1≤l ≤ 10000 ,为特制储物箱长度。接下来n行,分别为每本书的长度li,li≤l。

Output

每组数据输出一行,即csuxushu至少需要定多少储物箱。

Sample Input

1

10
80
70
15
30
35
10
80
20
35
10
30

Sample Output

6

这个题目也是挺坑的,需要的输出格式是2个数之间还有一个空行。

这个题目就是先排序后用贪心算法,虽然很难说清楚,不过算法应该是对的。

代码:

#include<iostream>
#include<algorithm>
using namespace std;
 
int list[100000];
 
int main()
{
    int t, n, l;
    int low, high;
    int sum;
    cin >> t;
    for (int ii = 0; ii < t;ii++)
    {
        cin >> n >> l;
        for (int i = 0; i < n; i++)cin >> list[i];
        sort(list, list + n);
        low = 0;
        high = n - 1;
        sum = 0;
        while (low < high)
        {
            if (list[low] + list[high] <= l)low++;
            high--;
            sum++;
        }
        if (low == high)sum++;
        cout << sum << endl<<endl;
    }
    return 0;
}

CSU 1926: 使用最少的硬币

题目:

Description

在小X生活的国家里,很多面额都有硬币。小X的存钱罐里有四种硬币,分别是5元的、10元的、20元的和50元。当他要付钱时,总是希望使用的硬币数量最少。现在告诉你小X拥有的四种硬币的数量,请你帮小X求出最好的付款方案(可能方案不存在)。

Input

输入包含不超过10组数据。 每组数据由一行五个用空格隔开的整数A、B、C、D、S组成(0<=A,B,C,D<=1000000,1<=S<=10000000),分别表示小X拥有的5元硬币、10元硬币、20元硬币和50元硬币的个数,以及小X现在需要付的钱数(单位:元)。

Output

对于每组数据,如果小X无法付款,则输出一行一个整数-1;否则输出一行五个用空格隔开的整数a、b、c、d、s,分别表示付款方案中小X需要用掉的5元硬币、10元硬币、20元硬币和50元硬币的数量,以及小X需要花费的总硬币数。

Sample Input

1 2 3 4 35
1 2 3 4 567

Sample Output

1 1 1 0 3
-1

代码:

#include<iostream>
#include<algorithm>
using namespace std;
 
int main()
{
	int A, B, C, D, S;
	while (cin >> A >> B >> C >> D >> S)
	{
		if (S % 5 || S % 2 && A == 0)
		{
			cout << -1 << endl;
			continue;
		}
		S /= 5;  //1,2,4,10
		int a, b, c, d, s;
		if (A > S % 2 + 1 || B > 0)//贪心
		{
			d = min(S / 10, D), S -= d * 10;
			c = min(S / 4, C), S -= c * 4;
			b = min(S / 2, B), S -= b * 2;
			a = min(S, A), S -= a;
			s = a + b + c + d;
			if (S)cout << -1 << endl;
			else cout << a << " " << b << " " << c << " " << d << " " << s << endl;
			continue;
		}
		a = S % 2, S /= 2;//2,5
		if (S % 2 && D == 0)
		{
			cout << -1 << endl;
			continue;
		}
		d = min((S-S%2*5) / 10, (D - S % 2) / 2) * 2 + S % 2, S -= d * 5;
		c = min(S / 2, C), S -= c * 2;
		b = 0;
		s = a + b + c + d;
		if (S)cout << -1 << endl;
		else cout << a << " " << b << " " << c << " " << d << " " << s << endl;
	}
	return 0;
}

CodeForces 538B Quasi Binary

题目:

Description

A number is called quasibinary if its decimal representation contains only digits 0 or 1. For example, numbers 0, 1, 101, 110011 — are quasibinary and numbers 2, 12, 900 are not.

You are given a positive integer n. Represent it as a sum of minimum number of quasibinary numbers.

Input

The first line contains a single integer n (1 ≤ n ≤ 106).

Output

In the first line print a single integer k — the minimum number of numbers in the representation of number n as a sum of quasibinary numbers.

In the second line print k numbers — the elements of the sum. All these numbers should be quasibinary according to the definition above, their sum should equal n. Do not have to print the leading zeroes in the numbers. The order of numbers doesn't matter. If there are multiple possible representations, you are allowed to print any of them.

Sample Input

Input

9

Output

9
1 1 1 1 1 1 1 1 1 

Input

32

Output

3
10 11 11

这个题目,首先要明确一点,不管输入的数是多少,我们所求的那些数加起来等于这个数,在加起来的过程中,绝对不会出现任何的进位现象。

要说证明的话倒也不难,不过应该是没有必要的。

总之,利用这个性质就可以轻松求解了。

代码:

#include<iostream>
#include<stack>
using namespace std;
 
stack<int>s;
 
int ff(int a, int b, int c, int d, int e, int f)
{
	int min = 10;
	if (a > 0 && min > a)min = a;
	if (b > 0 && min > b)min = b;
	if (c > 0 && min > c)min = c;
	if (d > 0 && min > d)min = d;
	if (e > 0 && min > e)min = e;
	if (f > 0 && min > f)min = f;
	if (min == 10)return 0;
	int x = (a >= min) * 100000 + (b >= min) * 10000 + (c >= min) * 1000 + (d >= min) * 100 + (e >= min) * 10 + (f >= min);
	for (int i = 0; i < min; i++)s.push(x);
	return ff(a - (a >= min)*min, b - (b >= min)*min, c - (c >= min)*min, d - (d >= min)*min, e - (e >= min)*min, f - (f >= min)*min) + min;
}
 
int main()
{
	int n;
	cin >> n;
	int a, b, c, d, e, f;
	if (n == 1000000)cout << 1 << endl << 1000000;
	else
	{
		f = n % 10;
		e = n / 10 % 10;
		d = n / 100 % 10;
		c = n / 1000 % 10;
		b = n / 10000 % 10;
		a = n / 100000;
		cout << ff(a, b, c, d, e, f) << endl;
		while (!s.empty())
		{
			cout << s.top() << " ";
			s.pop();
		}
	}
	return 0;
}

当然,仔细想一想的话,本题是不需要栈的。

代码:

#include<iostream>
#include<stack>
using namespace std;
 
void ff(int a, int b, int c, int d, int e, int f)
{
	int s = 0;
	if (a + b + c + d + e + f == 0)return;
	if (f)
	{
		f--;
		s += 1;
	}
	if (e)
	{
		e--;
		s += 10;
	}
	if (d)
	{
		d--;
		s += 100;
	}
	if (c)
	{
		c--;
		s += 1000;
	}
	if (b)
	{
		b--;
		s += 10000;
	}
	if (a)
	{
		a--;
		s += 100000;
	}
	cout << s << " ";
	ff(a, b, c, d, e, f);
}
 
int main()
{
	int n;
	cin >> n;
	int a, b, c, d, e, f;
	if (n == 1000000)cout << 1 << endl << 1000000;
	else
	{
		f = n % 10;
		e = n / 10 % 10;
		d = n / 100 % 10;
		c = n / 1000 % 10;
		b = n / 10000 % 10;
		a = n / 100000;
		int max = 0;
		if (max < a)max = a;
		if (max < b)max = b;
		if (max < c)max = c;
		if (max < d)max = d;
		if (max < e)max = e;
		if (max < f)max = f;
		cout << max << endl;
		ff(a, b, c, d, e, f);
		cout << endl;
	}
	return 0;
}

这个代码看起来就要简单好多。

其实差别不大,但是这个代码更明显的体现了一种贪心策略:

每次都输出一个数,使得它有尽可能的1,当然了,要是满足题目的条件的数。

猜你喜欢

转载自blog.csdn.net/nameofcsdn/article/details/112753449