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,t]之外的线段剔除,不作存储
- 按照区间左端点由小到大排序
- 遍历区间,更新变量(选取的区间数、当前最大的右端点值、当前需要线段覆盖的起点):
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;
}