A题 选数问题
题目描述
Given [Math Processing Error] positive numbers, ZJM can select exactly [Math Processing Error] of them that sums to [Math Processing Error]. Now ZJM wonders how many ways to get it!
input:
The first line, an integer [Math Processing Error], indicates the number of test cases. For each case, there are two lines. The first line, three integers indicate [Math Processing Error], [Math Processing Error] and [Math Processing Error]. The second line, [Math Processing Error] integers indicate the positive numbers.
output:
For each case, an integer indicate the answer in a independent line.
思路
这里将所有的数都存进一个数组,这个数组进行dfs递归操作,当递归k次后判断是否是正确,在k次之前就已经大于S就应该提前结束递归节省时间
代码
#include<iostream>
using namespace std;
int n,K,S,ans;
int a[100];
void dfs(int k,int sum,int end)
{
if(sum>S)return;//提前退出
if(k==K)
{
if(sum==S) ans++;
}
else
{
for(int i=end;i<n;i++)
dfs(k+1,sum+a[i],i+1);
}
}
int main()
{
int T;
cin>>T;
while(T--)
{
cin>>n>>K>>S;
for(int i=0;i<n;i++)
cin>>a[i];
ans=0;
dfs(0,0,0);
cout<<ans<<endl;
}
return 0;
}
总结
这次的作业我有罪啊,因为贪玩加上不注意看群里的通知,等到这次作业结束才发觉不对劲,o(╥﹏╥)o。
B题 区间选点
题目描述
数轴上有 n 个闭区间 [a_i, b_i]。取尽量少的点,使得每个区间内都至少有一个点(不同区间内含的点可以是同一个)
输入:
第一行1个整数N(N<=100)
第2~N+1行,每行两个整数a,b(a,b<=100)
输出:
一个整数,代表选点的数目
思路
这道题的题意很明确,这里我采用这样的贪心准则,取剩余区间中右节点最小的,用其左节点与基准点即之前选出的区间的右节点进行比较,如何小于右节点就可以共用一个点,否则就更新基准点为新区间的右节点。这里将所有的区间用右节点进行非递减排序,依次从中取元素。
代码
#include<iostream>
#include<algorithm>
using namespace std;
struct mm
{
int l,r;
mm(){};
mm(int a,int b):l(a),r(b){};
bool operator<(const mm&p)
{
return r<p.r;
}
};
mm shu[101];
int n;
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>shu[i].l>>shu[i].r;
}
sort(shu,shu+n);
int count=0,nowp=-1;
for(int i=0;i<n;i++)
if(shu[i].l>nowp)
{
nowp=shu[i].r;
count++;
}
cout<<count<<endl;
return 0;
}
总结
蒟蒻通过这道题可算是搞清楚了重载小于号还有cmp函数里小于号的小花招了,以下面cmp函数所示,a和b可以看做是数组中的前后两项,a<b也就表示排序后数组内的关系,本例为递增关系,而重载小于号时,调用的结构体或类可以看做为前者元素,函数内部表示和cmp函数一样,这里也是递增关系,菜鸡理解方式
bool operator<(const mm&p)
{
return r<p.r;
}
bool cmp(const int &a,const int &b)
{
return a<b;
}
C题 区间覆盖
题目描述
数轴上有 n (1<=n<=25000)个闭区间 [ai, bi],选择尽量少的区间覆盖一条指定线段 [1, t]( 1<=t<=1,000,000)。
覆盖整点,即(1,2)+(3,4)可以覆盖(1,4)。
input:
第一行:N和T 表示给定区间数和所要覆盖的区间右端点值
第二行至N+1行: 每一行一个闭区间。
output:
选择的区间的数目,不可能办到输出-1
思路
我们这次采用左端点非递减顺序进行排列,对于每个记录的左端点值,都要从数组中找到一个元素其左端点小于等于当前记录的左端点值,并且右端点值尽可能大的区间进行更新,这样才会用尽可能少的区间覆盖整个区间。
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
using namespace std;
struct mm
{
int l,r;
bool operator<(const mm&p)
{
return l<p.l;
}
};
mm shu[25002];
int n,T,S=1;
int main()
{
scanf("%d%d",&n,&T);
for(int i=0;i<n;i++)
{
scanf("%d%d",&shu[i].l,&shu[i].r);
}
sort(shu,shu+n);
int n_x=1,n_y=0,count=0;
int i=0;
while(n_x<=T&&i<n)
{
if(shu[i].l>n_x) break;
bool flag = 0;
for(;i<n&&shu[i].l<=n_x;i++)
{
if(shu[i].r>n_y)
{
n_y=shu[i].r;//更新最右值
flag=1;
}
}
if(flag)
{
count++;
n_x=n_y+1;
}
}
if(n_x>T) printf("%d\n",count);
else printf("-1\n");
return 0;
}
总结
开始没有考虑到flag的必要,对每次右端点值更新都进行count++造成结果很大,立一个flag表示更新了右值,这样就解决多次加一的问题。