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。不熟不熟还需努力。