20201020 day40 复习9:贪心综合练习(二)

艰苦卓绝的做题过程x2

1 怎么看电影&zdx看电影&活动安排

注:“怎么看电影”和“活动安排”是同一个题,由于洛谷没有该题,故使用了之前自己上传的题目。“zdx看电影”是多组数据,每组数据中做法相同。

problem

\(n\)个活动,分别有起止时间\([x,y)\),两个活动\([a,b),[c,d)\)不想交,则叫做这两个活动相容。求这\(n\)个活动中互相相容的活动个数最大值。

solution

贪心考察。把所有的活动起止时间映射在数轴上,我们可以选择结束时间尽可能早的点,这样可以继续选择更早开始的活动,使得全局更优。代码实现显然,复杂度\(O(n)\),多组数据\(O(Tn)\)

thoughts

debug:t1写成t。
100pts:贪心。

code

活动安排&怎么看电影

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read() {
    long long a = 0, op = 1;
    char c = getchar();
    while (c > '9' || c < '0') {
        if (c == '-')
            op = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        a *= 10, a += c ^ 48, c = getchar();
    }
    return a * op;
}
struct node {
    int num, l, r;
} a[1000005];
int t;
int k;
bool cmp1(node x, node y) { return x.r < y.r; }
int ans = 1, t1;
int main() {
    k = read();
    for (int i = 1; i <= k; i++) a[i].l = read(), a[i].r = read();
    sort(a + 1, a + k + 1, cmp1);
    t1 = a[1].r;
    for (int i = 2; i <= k; i++)
        if (a[i].l >= t1)
            ans++, t1 = a[i].r;
    printf("%d\n", ans);
    return 0;
}

zdx看电影(多组数据)

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read(){
	long long a=0,op=1;char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
	while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
	return a*op;
}
struct node {
	int num,l,r;
}a[1000005];
int t;
int k;
bool cmp1(node x,node y){
	return x.r<y.r;
}
int main(){
	t=read();
	while(t--){
		k=read();
		for(int i=1;i<=k;i++) a[i].num=read(),a[i].l=read(),a[i].r=read();
		//for(int i=1;i<=k;i++) printf("test:%d %d\n",a[i].l,a[i].r);
		sort(a+1,a+k+1,cmp1);
		//for(int i=1;i<=k;i++) printf("testxxx:%d %d\n",a[i].l,a[i].r);
		int t1=a[1].r,ans=1;
		for(int i=2;i<=k;i++) 
			if(a[i].l>=t1) ans++,t1=a[i].r;
		printf("%d\n",ans);
		for(int i=1;i<=k;i++) a[i].l=0,a[i].r=0;
	}
	return 0;
}

2 智力大冲浪

problem

\(n\)个活动,每个活动没有完成扣除的金额为\(p_i\),每个活动的完成时限为\(q_i\),在完成时限内没有完成会扣除相应金额。给定金额\(m\),求剩余的钱的最大值。

solution

如果遇到一个时限为\(k\)的活动,我们要尽可能的把它放到能放的\(\le k\)的位置。如果不能放,我们就把他放到最大的一个空时间段,这样避免影响之后的结果,也不会对结果产生影响,因为如果这件事情做不完,在任何情况下做不完扣除的钱都一样。

thoughts

100pts:一次AC。

code

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read(){
	long long a=0,op=1;char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
	while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
	return a*op;
}
int tim[505],n,s,x,mon[505],m;
struct node{
	int tim,mon;
}a[505];
int done[505];
bool cmp1(node x,node y){
	return x.mon>y.mon;
}
int main(){
	m=read();n=read();
	for(int i=1;i<=n;i++) a[i].tim=read();
	for(int i=1;i<=n;i++) a[i].mon=read();
	sort(a+1,a+n+1,cmp1);
	for(int i=1;i<=n;i++){
	 	x=1;
		for(int j=a[i].tim;j>=1;j--){
			if(done[j]==0) {x=0,done[j]=1;break;}
		}
		if(x){
			for(int k=n;k>=1;k--) 
				if(done[k]==0) {done[k]=1;break;}
			s+=a[i].mon;
		}
	}
	printf("%d",m-s);
	return 0;
}

3 雷达安装

problem

平面直角坐标系中,第I、II象限内有\(n\)个点,在\(x\)轴上寻找最少的\(k\)个点,使得以它们为圆心,\(d\)为半径的圆将所有的点覆盖。

solution

以每个点为圆心,d为半径做圆,每个点可以在\(x\)轴上得到一个区间,这样就转换成了在\(x\)轴上选点,使得每个区间内都至少有一个点。
我们按照右端点排序,如果下一个区间的右端点在前一个里面,我们可以跳过,否则我们就选择右端点最旁边的那个点(也就是那个点),显然这样更优。复杂度\(O(n)\)

thoughts

100pts:一次AC。

code

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <iostream>
#include <queue>
using namespace std;
int read(){
	long long a=0,op=1;char c=getchar();
	while(c>'9'||c<'0') {if(c=='-') op=-1;c=getchar();}
	while(c>='0'&&c<='9'){a*=10,a+=c^48,c=getchar();}
	return a*op;
}
const int maxn=1e4+5;
int n,d,ans,x[maxn],y[maxn];
double l[maxn],r[maxn],temp;
struct node{
	double l,r;
}a[maxn];
double cmp(node a,node b){return a.r<b.r;}
int main(){
	n=read(),d=read();
	for(int i=1;i<=n;i++) x[i]=read(),y[i]=read();
	for(int i=1;i<=n;i++) 
		a[i].l=x[i]-sqrt(d*d-y[i]*y[i]),
		a[i].r=x[i]+sqrt(d*d-y[i]*y[i]);
	sort(a+1,a+n+1,cmp);
	for(int i=1;i<=n;i++){
		if(i==1) temp=a[i].r,ans++;
		else{
			if(temp>=a[i].l) continue;
			else ans++,temp=a[i].r;
		}
	}
	printf("%d",ans);
	return 0;
}

4 整数区间

problem

给定\(n\)个区间\([a_i,b_i]\),选择最少的点,使得每个区间内至少有两个点,求选择点的个数。

solution

把区间先按右端点从小到大排序,开两个变量来记录位置(保证x < y)
如果区间右端点大于y,则这个区间者少有两个数被劝进集合中了,continue掉就好了
如果区间的右端点在x和y之间,把x变成y,y变成这个区间的左端点,同时ans++
如果区间的右端点小于x,x变成区间的左端点,y变成区间的右端点,同时ans+=2

thoughts

100pts:一次AC。

code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
struct node{
    int a;
    int b;
};
node m[1000];
bool cmp(node a,node b)
{
    if(a.a != b.a)
    {
        return a.a < b.a;
    }
    else
    return a.b < b.b;
}
int main()
{
    int n,f1,f2,tot = 0;
    cin>>n;
    for(int i = 1;i <= n;i++)
    {
        cin>>m[i].a>>m[i].b;
    }
    sort(m + 1,m + n + 1,cmp);
    f1 = m[n].a;
    f2 = m[n].a + 1;
    tot += 2;
    for(int i = n - 1;i > 0;i--)
    {
        if(m[i].b < f1)
        {
            tot += 2;
            f1 = m[i].a;
            f2 = f1 + 1;
        }
        else if(m[i].b < f2) 
        {
            tot ++;
            f2 = f1;
            f1 = m[i].a;
        }
    }
    cout<<tot<<endl;
    return 0;
}
posted @ 2020-10-20 08:43  刘子闻  阅读(82)  评论(0编辑  收藏  举报