SDU 程序设计思维与实践week3 作业【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!

输入描述

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.

输出描述

For each case, an integer indicate the answer in a independent line.
Remember that k<=n<=16 and all numbers can be stored in 32-bit integer》

输入样例

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

输出样例

4

思路分析

本题思路为DFS。从起点开始,分别DFS选第i个数与不选第i个数。注意可行性剪枝即可。

代码

#include<iostream>
#include<cstdio>
using namespace std;
int t,n,k,s,ans,arr[16];
void dfs(int sum,int i,int left){
	if(sum==s&&left==0) {
		ans++;return;
	}
	//可行性剪枝 
	if(i==n||sum>s||left==0||left>n-i) return;
	dfs(sum+arr[i],i+1,left-1);//选第i个数
	dfs(sum,i+1,left);//不选第i个数; 
	 
}
int main(){
	cin>>t;
	for(int i=0;i<t;i++){
		ans=0;
		cin>>n>>k>>s;
		for(int j=0;j<n;j++){
			cin>>arr[j];
		}
		dfs(0,0,k);
		cout<<ans<<endl; 
	} 
}

B 区间选点

题意描述

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

输入描述

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

输出描述

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

思路分析

将所有区间按b从小到大排序。依次遍历区间,若当前区间没有点,则选取最后一个点。

代码

#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
struct interval{
	int a,b;
	bool operator<(const interval & p) const{
		return b!=p.b? b<p.b:a>p.a;
	}
};
int n,ans,now;
vector<interval> v;
int main(){
	cin>>n;
	for(int i=0;i<n;i++){
		int a=0,b=0;
		cin>>a>>b;
		v.push_back({a,b});
	}
	sort(v.begin(),v.end());
	int now=v[0].b;ans++;
	for(int i=0;i<v.size();i++){
		if(!(v[i].a<=now&&v[i].b>=now)){
			ans++;now=v[i].b;
		}	
	}
	cout<<ans<<endl;
}

C 区间覆盖

题意描述

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

输入描述

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

输出描述

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

思路分析

1、区间数据整理,如果左端点<1则改为1,右端点>1则改为t。
2、按照a从小到大排序,遍历每个区间。

  • 如果当前区间的左端点 ≤ \leq 目前覆盖的区间的左端点,更新覆盖的右端点。
  • 否则,说明需要选择当前区间。如果当前区间的左端点 ≤ \leq 已覆盖区间的右端点+1.那么选取该区间,更新已覆盖的右端点。否则,说明无解。

代码

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
int n,t,ans;
struct interval{
	int a,b;
	bool operator<(const interval & p) const{
		return a!=p.a?a<p.a:b>p.b; 
	}
};
vector<interval> v;
int main(){
	int a=0,b=0;
	while(scanf("%d%d",&n,&t)!=EOF){
		v.clear();
		ans=1;
		for(int i=0;i<n;i++){
			scanf("%d%d",&a,&b);	
			if(a<1) a=1;
			if(b>t) b=t;
			v.push_back({a,b});
		}
		sort(v.begin(),v.end());
		int start=1,now=0,end=v[0].b;
		if(v[0].a!=1){
			cout<<"-1"<<endl;
			continue;
		}
		for(int i=0;i<n;i++){					
			if(v[i].a<=start){
				end=max(end,v[i].b);
			}
			else{
				ans++;
				start=end+1;
				if(v[i].a<=start){
					end=v[i].b;
				}else{
					ans=-1;break;
				}
			}
			if(end==t){
				break;
			}
			
		}
		if(end==t){
			cout<<ans<<endl; 
		}
		else{cout<<"-1"<<endl;
		}
		
		
	}
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值