Week3作业
A-选数问题
1.题意:给出N个正整数,问有多少种组合使得K个数相加为S。输入输出样例为:
Input
1 //表示有几组数
10 3 10 //分别是该组数的个数、每个组合里整数的个数、相加的和
1 2 3 4 5 6 7 8 9 10//该组数的成员
Output
4//结果,即有多少种组合
2.思路:对于此类子集枚举的问题,可使用bfs求解,同时为了提高代码效率避免超出运行时间,可以删去一些不必要的部分,比如sum<0或者选数个数大于k个时,直接结束循环。同时定义一个count来记录方案的种数,每当选数个数达到k且sum为0的时候(代码里是sum-a[j]),count就要加1。
3.代码:
#include <iostream>
#include <stdio.h>
#include <math.h>
#include <string.h>
using namespace std;
int count,n;
int a[100];
void bfs(int i,int j,int k,int sum)
{
if(i==k && sum==0)
{
count++;
return;
}
else if(i>k ||j>n-1 ||sum<0) return;
bfs(i,j+1,k,sum);
bfs(i+1,j+1,k,sum-a[j]);
}
int main()
{
int m,k,sum;
cin>>m;
for(int i=0;i<m;i++)
{
count=0;
cin>>n>>k>>sum;
for(int i=0;i<n;i++) cin>>a[i];
bfs(0,0,k,sum);
cout<<count<<endl;
}
return 0;
}
B-区间选点
1.题意:数轴上有n个闭区间。取尽量少的点,使每个区间都至少有一个点。
2.思路:为了比较方便的表示一个区间,可以使用一个结构体类型的数组,结构体中包含两个整数,分别表示该区间的左右端点;接着要判断两个区间是否有重合,先对区间进行排序,然后进行比较,若一个区间的右端点大于后一个区间的左端点,则这两个区间没有公共部分,点的数量加1,我这里还用了一个behand来记录每个区间的左端点并与其后面一个区间的右端点来比较,若满足(a[i].y<behand),则将a[i].x的值赋予behand,并进行下一轮比较,直至循环结束。
3.代码:
#include <iostream>
#include <algorithm>
using namespace std;
struct area
{
int x,y;
}a[100];
bool spot(area a,area b)
{
if(a.x!=b.x) return a.x>b.x;
else return a.y<b.y;
}
int main()
{
int n; cin>>n;
for(int i=0;i<n;i++) cin>>a[i].x>>a[i].y;
sort(a,a+n,spot);
int num=1,behand=a[0].x;
for(int i=1;i<n;i++)
{
if(a[i].y<behand)
{
behand=a[i].x;
num++;
}
}
cout<<num<<endl;
return 0;
}
C-区间覆盖
1.题意:数轴上有n个闭区间,选择尽量少的区间覆盖一条指定线段。覆盖整点,比如(1,2)+(3,4)可以覆盖(1,4)。无法办到,输出-1。
2.思路:本题开始的动态数组c[i]表示每个以i开始的线段中右端点的最大值,在确定区间[a,b]后,应将起点设置为b,使用贪心策略进行查找,直到到达右端点为止;int m=0,x;其中m表示最大值,x为取得最大值时的i,在循环过程中,若m小于上一个区间的右端点,则退出循环。
3.代码:
#include <iostream>
#include <cstring>
using namespace std;
int* c=new int[1000000];
int main()
{
int N,T;
while(scanf("%d%d",&N,&T)!=EOF)
{
for(int i=0;i<1000000;i++) c[i]=-1;
for(int i=0;i<N;i++)
{
int a,b;
scanf("%d%d",&a,&b);
if(c[a]<b) c[a]=b;
}