A — 选数问题 (DFS解题)
题目描述
Given n positive numbers, ZJM can select exactly K of them that sums to S. Now ZJM wonders how many ways to get it!
译文:从n个数中选K个,使得他们的和为S;
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.
译文:第一行输入T (<= 100),代表数据的总组数;对于每一组,其输入包括两行;第一行输入n,K,S,第二行,n个数据;
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
解题思路
vector< int > elements 用于存储输入的数;
list< int > e 用于存储选择的数;
DFS的过程就相当于是将所有的n个数进行组合,选择其中的K个进行求和;
参数:
int i — 所选数字在elements数组中的位置;
int sum —— 已选择数字的和;
list < int > e —— 存储选择的数;
在DFS过程中可以直接舍去的方案:
1、当选择的数超过n个的时候;
2、所选数字的和超过了S;
3、所选数字的个数超过了K;
解题代码
#include <iostream>
#include <vector>
#include <list>
#include <cmath>
using namespace std;
int T;
int n, K, S;
int solutions = 0;
int element;
vector<int> elements;
list<int> e;
void dfs(int i, int sum, list<int> e) {
if (sum == S && e.size() == K) {
solutions++;
return;
}
if (i >= n) {return;}
if (sum > S || e.size() > K) {return;}
solve(i + 1, sum, e);
e.push_back(elements[i]);
solve(i + 1, sum + elements[i], e);
e.pop_back();
}
int main()
{
cin>>T;
for (int a = 0; a < T; a++) {
cin>>n>>K>>S;
for (int b = 0; b < n; b++) {
cin>>element;
elements.push_back(element);
}
dfs(0, 0, e);
cout<<solutions<<endl;
elements.clear();
e.clear();
solutions = 0;
}
}
B — 区间选点 (贪心算法)
题目描述
数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)
Input
第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)
Output
一个整数,代表选点的数目
Sample Input
2
1 5
4 6
Sample Output
1
解题思路
核心:
对于一个区间[ a_i,b_i ],其右端点b_i 能够表示这一整个区间,所以在选择“在区间里面的点”时,应该是默认选择右端点b_i,这样能够使得每个区间内都至少有一个点;
存储区间信息:
自定义结构体interval包括一个区间的左右端点;
定义vector数组 vector< interval > i储存所有的区间,全部的区间信息录入之后,按照右节点从小到大的顺序进行排列;
存储所选择的点:
定义vector数组 vector< int > j;
j [0]一定是所有区间里面,右节点最小的那个,即 i [0]. f;
从i [1]开始进行循环,用int型变量 point 表示目前最大的所选择的点,当且仅当 point < i [n]. s,将这个端点值插入j 中,因为point 如果小于了一个区间的左端点,就代表目前选择的点不能保证每个区间里面都有一个点;
输出结果:
选择的点都存储在 j 中,那么所求结果即为 j 的容量的大小;
解题代码
#include <iostream>
#include <vector>
#include <list>
#include <algorithm>
#include <cmath>
using namespace std;
int N;
int a, b;
long int pointn;
int symbol;
struct interval {
int s;
int f;
};
bool PX(interval x, interval y){
if (x.f == y.f) {return x.s > y.s;}
return x.f < y.f;
}
vector<interval> i;
vector<int> j;
int main()
{
cin>>N;
interval c;
for (int n = 0; n < N; n++) {
cin>>a>>b;
c.s = a;
c.f = b;
i.push_back(c);
}
sort(i.begin(), i.end(), PX);
j.push_back(i[0].f);
int point = i[0].f;
for (int n = 1; n < N; n++) {
if (point < i[n].s) {
point = i[n].f;
j.push_back(i[n].f);
}
}
pointn = j.size();
cout<<pointn<<endl;
}
C — 区间覆盖
题目描述
数轴上有 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
解题思路
预处理
1、自定义结构体 interval : 包含左端点( int left ) 和右端点( int right );
2、输入数据: 不在目标区间[ 1, T ]内的,直接舍弃;仅有部分在的,例如仅有右边部分在目标区间内,将左端点置为1、仅有左边部分在的,将右端点置为T;
**3、vector< interval > t: ** 用于储存所有的区间;
排序
按照左端点由大到小排序,当左端点大小相等时,依据右端点从大到小排列;
求解过程
由所规定的排序规则可以得到,t [ 0 ] 一定是所有区间里面,左端点是1的区间长度最大的区间;
往后遍历其余的所有区间,满足如下几种条件的区间应该被选取:(用interval y储存最新被选取的区间)
**1、区间的左顶点 <= y. left && 区间右顶点 > y.right **: 选择该区间能够让总区间往前延伸,但是有一部分是与已选区间发生了重合;
2、区间的左顶点 == y.right + 1: 选择该区间能够往前延伸,且没有重合的部分;
选择的依据: 根据能够往前延伸的长度;对于情况1: L = 区间右顶点 - y. right;对于情况2:
L = 区间右顶点 - 区间左顶点 + 1;对于所有的选择,都是选择两种情况中最大的那个区间;
解题代码
#include <iostream>
#include <vector>
#include <list>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
int N, T;
int a, b;
struct interval {
int left;
int right;
};
bool PX(interval x, interval y) {
if (x.left == y.left) {return x.right > y.right;}
return x.left < y.left;
}
vector<interval> t;
int main()
{
cin>>N>>T;
interval x;
int intervaln = 1;
for (int w = 0; w < N; w++) {
scanf("%d %d", &a, &b);
if (b < 1 || a > T) {
continue;
}
else {
if (a < 1) {a = 1;}
if (b > T) {b = T;}
x.left = a; x.right = b;
t.push_back(x);
}
}
if (t.size() == 0) {
cout<<-1<<endl;
return 0;
}
sort(t.begin(), t.end(), PX);
//无法到达起点 1
if (t[0].left > 1) {
cout<<-1<<endl;
return 0;
}
interval y = t[0];
int chosen = 0;
while (y.right < T) {
int maxL = 0;
for (int w = chosen + 1; w < N; w++) {
if (t[w].left <= y.right && t[w].right > y.right) {
int L = t[w].right - y.right;
if (L > maxL) {
maxL = L;
chosen = w;
}
}
if (t[w].left == y.right + 1) {
int L = t[w].right - t[w].left + 1;
if (L > maxL) {
maxL = L;
chosen = w;
}
}
else
continue;
}
if (maxL == 0) {
cout<<-1<<endl;
return 0;
}
y = t[chosen];
intervaln++;
}
cout<<intervaln<<endl;
}