[Week3 homework] A-selection problem, B-interval point selection, C-interval coverage

A-selection question

Topic:

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

Ideas and practices:

Use the backtracking method to solve the problem.
Write a function backtrack and call this function recursively until it reaches the boundary or get a valid solution and then return back. First write the code to make the array of possible numbers in the array one by one to construct an array of possible solutions. It is very easy to use a loop here. First, do not recurse directly into the next layer, and put this number into the next layer, and then recurse, and realize that There are two cases of absence, and then all possible cases can be accessed. The key is that in order to optimize the time complexity, we need to pruning. We only need K numbers, then there is no need to continue recursion when the number in the array exceeds k; if the sum to be satisfied is less than 0, it means that the selected number is already greater than S, and does not meet the requirements of the solution, return directly; the current access The index of the number has exceeded the given array range, which is a boundary to be returned. If a suitable solution is found, record it and return directly.
After the entire backtrack ends, the recorded ans value is the answer.

to sum up:

Very basic backtracking problem, pay attention to how to write recursive functions, and how to effectively pruning.

Code:

#include <list>
#include <stdio.h>
using namespace std;
#define N 16
#define rep(i,s,t) for(int i=s;i<=t;i++)

list<int> nums;
int num[N],ans;

void backtrack(int start,int n,int k,int s){
	if(nums.size()==k&&s==0){
		ans++;
		return;
	}else if(nums.size()>k||s<0||start>=n){
		return;
	}else{
		rep(i,start,n-1){
			nums.push_back(num[i]);
			backtrack(i+1,n,k,s-num[i]);
			nums.pop_back();
		}
	}
}

int main(){
	int t;
	scanf("%d",&t);
	while(t--){
		int n,k,s;
		while(!nums.empty()) nums.pop_back();
		ans=0;
		scanf("%d %d %d",&n,&k,&s);
		rep(i,0,n-1){
			scanf("%d",&num[i]);
		}
		backtrack(0,n,k,s);
		printf("%d\n",ans);
	}
	return 0;
}

B-interval selection

Topic:

There are n closed intervals [a_i, b_i] on the number line. Take as few points as possible so that there is at least one point in each interval (the points contained in different intervals can be the same)

Input

1 integer N in the first line (N <= 100)
Line 2 ~ N + 1, two integers a, b in each line (a, b <= 100)

Output

An integer representing the number of points selected

Sample Input1

2
1 5
4 6

Sample Output1

1

Sample Input2

3
1 3
2 5
4 6

Sample Output2

2

Ideas and practices:

Use greedy strategy to solve the problem of interval selection.
The first is to choose a greedy criterion and find a solution based on this criterion. The greedy criterion used here is sorting from the smallest end to the right end of the interval. The small first means that the interval ends early and the next interval ends late. See if the left end point of the next interval is inside the interval in front of it. If it is, there is no need to cover the extra points, otherwise you need to add an extra point. At its right end, to cover this point, and then loop down. After going through it again, the number of points is the solution.

to sum up:

Pay attention to the selection of the greedy criterion, and think of a criterion. If you cannot achieve mathematical proof, find out if there is a counterexample to overthrow. The guideline for this topic is relatively easy. It is possible to use a variable end to record the current right endpoint and keep updating it.

Code:

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

struct Interval{
	int a,b;
	Interval(){}
	Interval(int _a,int _b):a(_a),b(_b){}
	bool operator<(const Interval& i){
		return b<i.b;
	}
}interval[N];

int main(){
	int n,a,b;
	scanf("%d",&n);
	for(int i=0;i<n;i++){
		scanf("%d %d",&a,&b);
		interval[i]=Interval(a,b);
	}
	sort(interval,interval+n);
	int ans=1,end=interval[0].b;
	for(int i=1;i<n;i++){
		if(interval[i].a>end){
			ans++;
			end=interval[i].b;
		}
	}
	printf("%d\n",ans);
	return 0;
} 

C-interval coverage

Topic:

There are n (1 <= n <= 25000) closed intervals [ai, bi] on the number line. Choose as few intervals as possible to cover a specified line segment [1, t] (1 <= t <= 1,000,000).
Cover the whole point, ie (1,2) + (3,4) can cover (1,4).
Impossible to do output -1

Input

The first line: the
second line of N and T to the N + 1 line: each line has a closed interval.

Output

The number of selected intervals cannot be output -1

Sample Input

3 10
1 7
3 6
6 10

Sample Output

2

Ideas and practices:

It can be understood that the minimum number of cells is selected to cover a large interval, and the cells should be as long as possible, and they can be covered from beginning to end to be covered by greedy methods. Roughly speaking, given a limit end (the initial end locates the beginning of a large interval), we need to select the left endpoint from the remaining intervals to the left of the limit (if it is on the right, it is disconnected and cannot be completely covered), and the right endpoint is away The farthest interval (the longer the length, the total number of corresponding intervals may decrease), then update end to the right end of the selected interval (specifically implemented on function f, return the index value of the most suitable interval found, can't find To the appropriate return -1). Loop until the existing end reaches or exceeds the right end of the large range to be covered, or no feasible solution is found, and return to ans.

to sum up:

The first thought was to edit the interval from the time of input, so as to sort and recycle according to the left endpoint and the calculated interval length, and update the left endpoint and length between each cell synchronously at each update end. Later, it was found that such trouble is also easy to make mistakes. The length of the interval is no longer calculated, and the distance between the right end of the interval and the end is directly compared.

Code:

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

struct Interval{
	int a,b;
	Interval(){}
	Interval(int _a,int _b):a(_a),b(_b){}
	bool operator<(const Interval& i) const{
		if(a!=i.a) return a<i.a;
		return b>i.b;
	}
}interval[N];

int f(int start,int end,int num){
	int ans=-1,min=-1;
	for(int i=start;i<end;i++){
		if(interval[i].a<=num+1&&interval[i].b>=num+1){
			if(interval[i].b-num-1>min){
				min=interval[i].b-num-1;
				ans=i;
			}
		}else if(interval[i].a>num+1) break;
	}
	return ans;
}

int main(){
	int n,t;
	while(~scanf("%d %d",&n,&t)){
		int cnt=0,a,b;
		for(int i=0;i<n;i++){
			scanf("%d %d",&a,&b);
//			if(a<=1&&b>=1&&b<=t) interval[cnt++]=Interval(1,b);
//			else if(b>t&&a>=1&&a<=t) interval[cnt++]=Interval(a,t);
//			else if(a>=1&&b<=t) interval[cnt++]=Interval(a,b);
//			else if(a<1&&b>t) interval[cnt++]=Interval(1,t);
			if(a<=t&&b>=1) interval[cnt++]=Interval(a,b);
		}
		sort(interval,interval+cnt);
		int ans=0,index=0,end=0;
		while(end<t){
			index=f(index,cnt,end);
			if(index==-1){  //没找到,断了 
				ans=-1;
				break;
			}
			ans++;  //找到,结果+1 
			end=interval[index].b;  //更新end 
		}
		printf("%d\n",ans);
	}
	return 0;
}
Published 10 original articles · Likes0 · Visits 231

Guess you like

Origin blog.csdn.net/weixin_44898140/article/details/104852181