WEEK3 作业

本周只有作业,主要考察上课讲的dfs和贪心

A 选数问题

题目描述:给定n个数从中选出k个使其和为sum,总共有多少种方法
思路:枚举子集->剪枝:在递归的过程中是否总数超过k或者和超过s,如果是则直接跳出,能够有效的减少递归的路径。

#include <stdio.h>
using namespace std;
int a[20]; 
bool vis[20];//表示该数是否用过 
int ans=0;
int n=0,m=0,k=0,s=0;

void solve(int index,int nk,int ns)//当前编号,当前个数,当前和 
{
	if(nk==k&&ns==s)
		ans++;
	if(index==n||nk==k||ns>s)//剪枝
		return;
	for(int i=index;i<n;i++)
	{//from index 不会重复 
		if(!vis[i])
		{
			vis[i]=true;
			solve(i+1,nk+1,ns+a[i]);
			vis[i]=false;
		}
	}
}

int main()
{
	scanf("%d",&m);//组数
	for( int i=1;i<=m;i++ )
	{
		scanf("%d%d%d",&n,&k,&s);
		for(int i=0;i<n;i++)
		{
			scanf("%d",&a[i]);
		}
		solve(0,0,0);
		printf("%d\n",ans);
		ans=0;
		for(int i=0;i<n;i++)
			a[i]=0;
	 } 
	return 0;
 } 
 /*1
10 3 10
1 2 3 4 5 6 7 8 9 10*/

B 区间选点

题目描述:数轴上有 n 个闭区间,取尽量少的点,使得每个区间内都至少有一个点
思路:利用贪心的思路,将区间按b从小到大排序,b相同时a从大到小排,第一个区间取最后一个点即可保证最后取的点最少。

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

struct interval
{
	int a,b;
	bool operator<(const interval &p) const
	{
		if(b!=p.b) return b<p.b;
		if(a!=p.a) return a>p.a;
		else return false; 
	}
}interval[105];

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

C 区间覆盖问题

题目描述:数轴上有 n个闭区间,选择尽量少的区间覆盖一条指定线段 [1, t]
思路:贪心,先将给定的所有区间按照要覆盖的区间进行裁剪,然后从起点开始选择终点最右的区间,并将其+1设为新的起点。
tips:一开始做的时候是每次更新需要覆盖的区间时就对所有的给定区间裁剪+排序一次,浪费大量时间直接TLE,后将算法进行优化,只对区间排序一次,每次选出区间后标记其位置,下次寻找时直接从此处开始

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

int n,t,j=0;
int maxr=0;
int tmp=0;

struct interval
{
	int a,b;
	bool operator<(const interval &p) const
	{
		if(a!=p.a) return a<p.a;
		if(b!=p.b) return b<p.b;
		else return false; 
	}
}interval[25010];

int main()
{
	scanf("%d%d",&n,&t);
	for(int i=0;i<n;i++)
	{
		scanf("%d %d",&interval[i].a,&interval[i].b);
		if(interval[i].a<1) interval[i].a=1;
		if(interval[i].b>t) interval[i].b=t; 
	}
	sort(interval,interval+n);
	
	int ans=0;
	int begin=1;
	
	if(interval[0].a>1) 
	{
		ans=-1;
	}
	
	while(begin<=t)
	{
		maxr=0;
		for(j=tmp;j<n&&interval[j].a<=begin;j++)
			maxr=max(maxr,interval[j].b);//选出最大的右边界 
			
		if(maxr>=begin) 
		{
			begin=maxr+1;
			ans++;
			tmp=j;
		}
		else 
		{
			ans=-1;
			break;
		}
	}
	printf("%d",ans);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值