程序设计作业week03

A - 选数问题

题目
在这里插入图片描述在这里插入图片描述样例
Input

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

Output

4

解题思路

选数问题可以用dfs解决,选择一个数向前继续探索,选下一个数,一旦发现不符合条件或者达到要求就返回,回溯到上一层,在上一层继续选择。

dfs
把可供选择的数都存在a数组里。定义函数dfs(int sum, int k, int j),sum为当前所选的数的和,初始值为0;k表示已经选了多少个数,初始值为0;j表示上一个加入的数的下标,初始值为0.

当k==K时,返回上一层。同时若这k个数的和正好是S,则解的个数++。否则从上一层所选的数字后面一个数a[j+1]开始遍历,选择数字a[i],然后递归dfs(sum+a[i], k+1, i+1)。

完整代码

#include <iostream>
using namespace std;
int T,K,n,S;
int cnt = 0;	//解的数量 
int a[20];	//可选的数 
void dfs(int sum, int k, int j)
{
	if(k == K)
	{
		if(sum ==S)
		cnt++;
		return;
	}
	for(int i=j;i<n;i++)
	{
		dfs(sum+a[i], k+1, i+1);	
		//选数加和 计数加一 只往后开始选避免重复 
	}
}
int main()
{
	cin>>T;
	for(int i=0;i<T;i++)
	{
		cnt = 0; 
		cin>>n>>K>>S;
		for(int j=0;j<n;j++)
			cin>>a[j];
		dfs(0, 0, 0);
		cout<<cnt<<endl;
	}
	return 0;
}

B - 区间选点

题目
在这里插入图片描述样例

Input

2
1 5
4 6

Output

1

Input

3
1 3
2 5
4 6

Output

2

解题思路

将所有的区间[a,b]按照b从小到大排序(b 相同时 a 从大到小排序)。排序使用sort函数,自定义cmp。

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

首先选中最小的b0,数字b0可以满足任何[ ,b0]的区间。然后判断b0是否在区间[ ,b1]中,若在,则不用更新继续向后判断;若不在区间中,则更新b为b1,计数++。以此类推,遍历区间数组判断。

int ed = s[0].b;
	int cnt = 1;
	for(int i=1;i<n;i++)
	{
		if(ed < s[i].a)
		{
			ed = s[i].b;
			cnt++;
		}
	}

完整代码

#include <iostream>
#include <algorithm>
using namespace std;
int n;

struct sec
{
	int a, b;
}s[110];

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

int main()
{
	cin>>n;
	for(int i=0;i<n;i++)
	{
		cin>>s[i].a>>s[i].b;
	}
	sort(s, s+n, cmp);
	int ed = s[0].b;
	int cnt = 1;
	for(int i=1;i<n;i++)
	{
		if(ed < s[i].a)
		{
			ed = s[i].b;
			cnt++;
		}
	}
	cout<<cnt<<endl;
	return 0;
}

C - 区间覆盖

题目
在这里插入图片描述在这里插入图片描述样例

Input

3 10
1 7
3 6
6 10

Output

2

解题思路

预处理:[s, t] 之外的部分切掉
相互包含:不考虑小区间
按 a 从小到大排序,区间 1 的起点不是 s,无解;否则选择起点在 s 的最长区间。选择区间 [ai, bi] 后的起点应设置为 bi,并切掉 bi 之前的部分。

将区间数组按 a 从小到大排序

bool cmp(sec x, sec y)
{
    return x.a<y.a;
}

设初始选定区间为(1,1),遍历区间数组扩展区间。
循环的终止条件是已经覆盖到所求区间。循环时需要判断的情况较多。
若区间断开,即后续的区间左端点与已覆盖区间的右端点之差大于1,则不能做到,应该跳出循环输出-1;若没有断开则遍历后面的区间,如果有区间包含的情况则选择大区间并更新右端点。在遍历到最后一个区间时也要特殊判断,看是否到最后一个区间能覆盖所求区间。

完整代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int num, tt;
int ll, rr;
int i,j,cnt;
bool judge;
struct sec
{
    int a, b;
}s[25100];
bool cmp(sec x, sec y)
{
    return x.a<y.a;
}
void init()
{
    scanf("%d %d", &num, &tt);
    for(int i=0;i<num;i++)
    {
        scanf("%d %d",&s[i].a,&s[i].b);
    }
    sort(s, s+num, cmp);
    ll = 1;
    rr = 1;
    i = 0;
    j = 0;
    cnt = 0;
    judge = 0;
}
void out_put(bool jd)
{
    if(jd == 1)       
            printf("-1\n");
        else    
            printf("%d\n", cnt);
}
int main()
{
        init();
        while(ll<=tt)
        {
            if(s[j].a>ll)
            {
                judge = 1;
                break;
            }
            for(i=j;i<num;i++)
            {
                if(s[i].a<=ll && s[i].b>=rr)
                    rr = s[i].b;
                else if(s[i].a>ll)
                {
                    ll = rr + 1;
                    cnt++;
                    j = i;
                    break;
                }
            }
            if(i == num)
            {
                cnt++;
                if(rr<tt)
                    judge = 1;
                break;
            }
        }
        out_put(judge);   
    return 0;
}

这是一个感想

个人不是很会写递归hhhhh,之前把一些经典简单的dfs问题,比如迷宫八皇后单词接龙什么的写过一遍后感觉好了些,这里的A题就不是很难。B题和C题是有关区间的贪心问题,本菜第一次接触。这种题关键点在于对区间按一定方法进行排序,然后确定选择方案,感觉有点难,特别是C题orz。C题最开始在群里跟别人讨论了一段时间才捋清了思路,然后才开始写,最开始还因为某行代码在调试的时候改忘了给崩了qwq。不熟不熟还需努力。

发布了10 篇原创文章 · 获赞 3 · 访问量 757

猜你喜欢

转载自blog.csdn.net/wakeupshely/article/details/104694925