程序设计思维与实践 Week3 作业3道

本周主要是DFS的学习,剪枝的优化练习及贪心算法的练习。

A - 选数问题

Given n positive numbers, ZJM can select exactly K of them that sums to S. Now ZJM wonders how many ways to get it!

Input

The first line, an integer T<=100, indicates the number of test cases. For each case, there are two lines. The first line, three integers indicate n, K and S. The second line, n integers indicate the positive numbers.

Output

For each case, an integer indicate the answer in a independent line.

Sample Input

1
10 3 10
1 2 3 4 5 6 7 8 9 10

Sample Output

4

Note

Remember that k<=n<=16 and all numbers can be stored in 32-bit integer

分析

注意到k<=n<=16,每个数包括选与不选两种情况,枚举每一个共2^16种,可以用int,来验证其是否符合要求,但是需要进行可行性剪枝操作,及时终止来降低复杂度。共有两种情况需要剪枝:选的数的个数超过了K,选的数的和超过了sum。其中用list记录被选的数,此时需要迭代一次次进行下一次数的操作。

C++

#include<iostream>
#include<list>
using namespace std;

int t, n, k, s, x, c;
void solve(int i, int sum, list<int>&res,int a[]) {
	if (res.size() == k && sum == 0) {
		c++;
		return;
	}
	if (i >= n)return;//搜索边界
	if (res.size() > k || sum < 0)return;//可行性剪枝

	solve(i + 1, sum, res, a);//不选,不放进去

	res.push_back(a[i]);//放进去
	solve(i + 1, sum - a[i], res, a);//选
	
	res.pop_back();//弹出来,进行一个的选与不选操作
}

int main() {
	list<int> number;
	while (cin >> t) {
		for (int i = 0; i < t; i++) {
			cin >> n >> k >> s;
			c = 0;
			int a[16];
			for (int j = 0; j < n; j++) {
				cin >> a[j];
			}
			solve(0, s, number, a);//从第1个开始进行枚举
			cout << c << endl;
		}
	}
	return 0;
}

B - 区间选点(编译器选GNU G++)

数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)

Input

第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)

Output

一个整数,代表选点的数目

Sample Input 1

2
1 5
4 6

Sample Output 1

1

Sample Input 2

3
1 3
2 5
4 6

Sample Output 2

2

分析

这是贪心算法的一个应用,主要是要确定贪心指标。即重叠区间越大,所取的点的数量越少,可以将区间按b从小到大的顺序排列,当b相同时a从大到小进行排列,找到下一个左右都不重叠的区间时,取的点的数量++,遍历直到最后一个区间分析完毕。

C++

#include<iostream>
#include<algorithm>
using namespace std;

bool compare(pair<int,int>& a1, pair<int,int>& a2) {
	return a1.second == a2.second? a1.first > a2.first: a1.second < a2.second; //按b从小到大的顺序排列,当b相同时a从大到小进行排列
}

int main() {
	int n;
	pair<int, int> itv[100];
	while (cin >> n) {
		for (int i = 0; i < n; i++) {
				cin >> itv[i].first>>itv[i].second;
		}
		sort(itv, itv + n, compare);
		int sum = 1, t = itv[0].second;
		for (int i = 0; i < n; i++) {
			if (itv[i].first > t) {
				sum++;
				t = itv[i].second;//更新
			}
		}
		cout << sum << endl;
	}
	return 0;
}

C - 区间覆盖(不支持C++11) (重点!!!)

描述

数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
不可能办到输出-1

Input

第一行:N和T
第二行至N+1行: 每一行一个闭区间。

Output

选择的区间的数目,不可能办到输出-1

Sample Input

3 10
1 7
3 6
6 10

Sample Output

2

提示

这道题输入数据很多,请用scanf而不是cin(scanf运行时间会减少,中文注释减少时间也会减少)

分析

这里的贪心指标是从起点开始的最长的一段,开始的起点是1,后来的起点是前一段最长起点的b+1,再遍历找下一个最长区间,思路比较简单。

C

#include<algorithm>
#include<stdio.h>
using namespace std;

bool compare(const pair<int, int> &a, const pair<int, int> &b) {
	return a.first < b.first;
}

int main() {
	int n, t, maxOfB, begin = 0, count = 0, index;
	pair<int, int> ivt[25001];
	while (~scanf("%d%d",&n,&t)) {
		for (int i = 0; i < n; i++) {
			scanf("%d%d",&ivt[i].first ,&ivt[i].second);
		}
		sort(ivt, ivt + n, compare);
		if (ivt[0].first > 1) {
			printf("%d\n",-1 ); //起始点大于1,未覆盖
			continue;
		}
		maxOfB = ivt[0].second, index = 0;
		for(int i = 0;i<n;i++){
			int j = i;
			while (ivt[j].first <= begin + 1 && j < n)
			{//该层循环中进行满足可以连接上一段的最大长度的查找,注意begin+1
				if (ivt[j].second>maxOfB)
				{
					maxOfB = ivt[j].second;
					index = j;//记录这个最大值的下标
				}
				j++;
			}
			count++;
			begin = ivt[index].second;//更新下一段的起始值大小
			if (maxOfB >= t  ) break;//覆盖了的话直接退出
		}
		if (maxOfB < t) {
			printf("%d\n", -1);未覆盖
			continue;
		}
		printf("%d\n", count); ;
	}
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值