week3作业:DFS+贪心算法

A——选数问题

题意

有N个正整数,在其中选出K个数使其和为S,求出有多少种取法。
测试样例:

  • 输入:
1
10 3 10
1 2 3 4 5 6 7 8 9 10
  • 输出
4

思路

使用dfs方法遍历:函数传递的参数为当前元素下标、需要得到的和及需要的元素个数。根据条件,每个数取或不取,直到需要得到的和为0且不再需要元素为止。

代码

#include<cstdio>
using namespace std;

const int MAXN=100;
int n,K,S;
int numbers[MAXN];
int visit[MAXN];
int method;

void dfs(int num,int kLeft,int sLeft){
	if(kLeft==0&&sLeft==0){
		method++;
		return;
	}
	if(num>=n) return;
	visit[num]=false;
	dfs(num+1,kLeft,sLeft);
	if(sLeft>=numbers[num]){
		visit[num]=true;
		dfs(num+1,kLeft-1,sLeft-numbers[num]);
	}
}

int main(void){
	int T;
	scanf("%d",&T);
	while(T--){
		method=0;
		scanf("%d%d%d",&n,&K,&S);
		for(int i=0;i<n;++i)
			scanf("%d",&numbers[i]);

		dfs(0,K,S);
		printf("%d\n",method);
	}
	return 0;
}

B——区间选点

题意

有n个闭区间,选取尽量少的点,使每个区间内都含有点。
测试样例:

  • 输入:
2
1 5
4 6
  • 输出:
1

思路

按照右端点值从小到大排序,相同时按左端点从大到小排序。遍历n个区间,以选取最小右端点为准则,若下一个区间左端点大于当前选择的点,则更新选择的点,且选点总数加1。

总结

问题定位:贪心算法

代码

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

const int MAXN=105;
struct INTERVAL{
	int a;
	int b;
	INTERVAL(){}
	INTERVAL(int _a,int _b):a(_a),b(_b){}
};
int N;
INTERVAL interval[MAXN];

bool cmp(const INTERVAL x,const INTERVAL y){
	if(x.b!=y.b)
		return x.b<y.b;
	else
		return x.a>y.a;
}

int main(void){
	scanf("%d",&N);
	for(int i=0;i<N;++i){
		int a,b;
		scanf("%d%d",&a,&b);
		interval[i]=INTERVAL(a,b);
	}
	sort(interval,interval+N,cmp);

	int pointNum,chosedPoint;
	for(int i=0;i<N;++i){
		if(i==0){
			pointNum=1;
			chosedPoint=interval[i].b;
		}
		else if(chosedPoint<interval[i].a){
			pointNum++;
			chosedPoint=interval[i].b;
		}
	}
	printf("%d\n",pointNum);
	return 0;
}

C——区间覆盖

题意

有n个区间,选择尽量少的区间覆盖[1, t]。
注:[1,2], [3,4]能覆盖[1,4]
测试样例:

  • 输入:
3 10
1 7
3 6
6 10
  • 输出:
2

思路

  1. 输入时的预处理:先将在区间[1,t]之外的线段剔除,不作存储
  2. 按照区间左端点由小到大排序
  3. 遍历区间,更新变量(选取的区间数、当前最大的右端点值、当前需要线段覆盖的起点):
    step1:选取从当前起点开始能覆盖区间的最大右端点,选取的区间数+1
    step2:判断是否能选择。当选取最大右端点的循环已完全遍历所有区间,跳出;当下一个区间左端点不等于最大右端点+1,即产生断点时,跳出;其余情况均更新区间起点进行下一次选择。
    step3:当最大右端点小于t,则不能覆盖,否则能覆盖。

总结

问题定位:贪心算法

代码

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

const int MAXN=100000001;
struct INTERVAL{
	int a;
	int b;
} interval[MAXN];
int N,T;
bool comp(const INTERVAL x,const INTERVAL y){
	return x.a<y.a;
}

int main(void){
	while(scanf("%d%d",&N,&T)!=EOF){
		int n=0;
		for(int i=0;i<N;i++){
			int a,b;
			scanf("%d%d",&a,&b);
			if(a>T||b<1) continue;
			interval[n].a=a;
			interval[n].b=b;
			n++;
		}
		sort(interval,interval+n,comp);

		int count=0,maxRight=-1,start=1;
		for(int i=0;i<n&&start<=T;){
			for(;i<n&&interval[i].a<=start;i++)
				maxRight=max(maxRight,interval[i].b);
			count++;

			if(i==n) break;
			if(interval[i].a>maxRight+1) break;
			start=maxRight+1;
		}
		if(maxRight<T) printf("%d\n",-1);
		else printf("%d\n",count);
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是用 C 语言实现该日历程序的示例代码: #include <stdio.h> int IsLeapYear(int year) { int flag = 0; if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) { flag = 1; } return flag; } int Calculation(int year, int month) { int sum = 0; int s_year = 1990; while (s_year < year - 1) { s_year++; if (IsLeapYear(s_year)) { sum += 366; } else { sum += 365; } } int s_month = 1; while (s_month < month) { if (s_month == 1 || s_month == 3 || s_month == 5 || s_month == 7 || s_month == 8 || s_month == 10 || s_month == 12) { sum += 31; } else if (s_month == 2) { if (IsLeapYear(year)) { sum += 29; } else { sum += 28; } } else { sum += 30; } s_month++; } return sum; } void Display(int sum, int year, int month) { int week = (sum + 1) % 7; int day; if (month == 1 || month == 3 || month == 5 || month == 7 || month == 8 || month == 10 || month == 12) { day = 31; } else if (month == 2) { if (IsLeapYear(year)) { day = 29; } else { day = 28; } } else { day = 30; } printf("日 一 二 三 四 五 六\n"); int count = 0; int space = 0; while (space <= week) { space++; count++; printf(" "); if (count % 7 == 0) { printf(" "); } } int days = 1; while (days <= day) { printf("%-3d ", days); days++; count++; if (count % 7 == 0) { printf("\n"); } } } int main() { int year, month; char choose; do { printf("输入年:"); scanf("%d", &year); if (year < 1990 || year > 9999) { printf("year输入错误\n"); continue; } printf("输入月:"); scanf("%d", &month); if (month < 1 || month > 12) { printf("month输入错误\n"); continue; } int sums = Calculation(year, month); Display(sums, year, month); printf("\n是否继续:(y/n)"); scanf(" %c", &choose); } while (choose == 'y' || choose == 'Y'); return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值