upc【贪心】专题

今天是被贪心统治的一天QAQ

【贪心】活动安排3
时间限制: 1 Sec 内存限制: 128 MB

题目描述
设有n个活动的集合E={1,2,…,n},其中每个活动都要求使用同一资源,如演讲会场等,而在同一时间内只有一个活动能使用这一资源。每个活动i都有一个要求使用该资源的起始时间si和一个结束时间fi,且si<fi。如果选择了活动i,则它在时间区间[si,fi)内占用资源。若区间[si,fi)与区间[sj,fj)不相交,则称活动i与活动j是相容的。也就是说,当fi≤sj或fj≤si时,活动i与活动j相容。选择出由互相兼容的活动组成的最大集合。
输入
第一行一个整数n(1≤n≤1000);
接下来的n行,每行两个整数si和fi。
输出
输出互相兼容的最大活动个数。
样例输入 Copy
4
1 3
4 6
2 5
1 7
样例输出 Copy
2

思路:
只有一个资源,说明一次只能进行一种活动,要尽量安排上下衔接最密切的活动,所以我们按照结束时间排序,将这一次的结束时间与下一次的开始时间进行比较,如果符合就加一,遍历所有活动

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#incldue<algorithm>
struct node{
	int e,b;
}a[1003];
int cmp(node x,node y)
{
	return x.e < y.e;
}
int main()
{
	int n,ans = 0;
	scanf("%d",&n);
	for(int i = 1;i <= n;i++)
	{
		scanf("%d%d",&a[i].b,&a[i].e);
	}
	sort(a + 1,a + n + 1,cmp); 
	int t = 0;
	for(int i = 1;i <= n;i++)
	{
		if(a[i].b >= t)
		{
			ans++;
			t = a[i].e;
		}
	}
	printf("%d",ans);
	return 0;	
}

【贪心】电视节目安排
时间限制: 1 Sec 内存限制: 64 MB

题目描述
李旭琳发现小墨老师在班上是最顽劣的学生(没有之一),但他也有安静的时候,例如在看电视的时候。像什么“谍战剧”啊,“翻拍剧”啊,“婆媳戏”啊,“后宫剧”啊都是他的最爱。他甚至会事先查询所有喜欢看的电视节目的转播时间表并煞有介事的用红蓝铅笔列出计划,然后合理安排,以看到尽量多的完整节目。
输入
输入数据包含多个测试实例,每个测试实例的第一行只有一个整数n(n≤100),表示喜欢看的节目的总数,然后是n行数据,每行包括两个数据Ti_s,Ti_e (1≤i≤n),分别表示第i个节目的开始和结束时间,为了简化问题,每个时间都用一个正整数表示。n=0表示输入结束,不做处理。
输出
对于每个测试实例,输出能完整看到的电视节目的个数,每个测试实例的输出占一行。
样例输入 Copy
12
1 3
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
5 10
4 14
2 9
0
样例输出 Copy
5

思路:
题目要求要尽量多看完整节目,所以我们应该按结束时间从小到大排序,然后从前向后遍历根据结束时间来判断开始时间是否符合要求,当结束时间相同时,应按照开始时间从小到大排序

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#include<algorithm>
struct node
{
	int begin;
	int end;
}a[100];
bool cmp(node b,node c)
{
	return (b.end < c.end) || (b.end==c.end && b.begin<c.begin);
	//首先按结束时间升序排序,当结束时间相同时,按开始时间升序排序 
}
int main()
{
	int n;	scanf("%d",&n);
	while(n != 0)
	{
		for(int i=0;i<n;i++)
			scanf("%d%d",&a[i].begin,&a[i].end);
		sort(a,a+n,cmp);
		int k = 0;
		int cnt = 1;
		for(int i=1;i<n;i++)
			if(a[i].begin >= a[k].end)
			//当第二个的开始时间大于等于第一个的结束时间时,cnt++,并把当前的i赋给k 
			{
				cnt++;	k = i;
			}
		printf("%d\n",cnt);
		cin >> n;
	}
	return 0;
}

【贪心】种树
时间限制: 1 Sec 内存限制: 128 MB

题目描述
一条街的一边有几座房子。因为环保原因居民想要在路边种些树。路边的地区被分割成块,并被编号成1…N。每个部分为一个单位尺寸大小并最多可种一棵树。每个居民想在门前种些树并指定了三个号码B,E,T。这三个数表示该居民想在B和E之间最少种T棵树。当然,B≤E,居民必须记住在指定区不能种多于区域地块数的树,所以T≤E-B+l。居民们想种树的各自区域可以交叉。你的任务是求出能满足所有要求的最少的树的数量。

写一个程序计算最少要种树的数量。
输入
第一行包含数据N,区域的个数(0<N≤30000);
第二行包含H,房子的数目(0<H≤5000);
下面的H行描述居民们的需要:B E T,0<B≤E≤30000,T≤E-B+1。
输出
树的数目。
样例输入 Copy
9
4
1 4 2
4 6 2
8 9 2
3 5 2
样例输出 Copy
5

思路:
满足所有居民种树要求时,所需要种的树的数量最少,就要尽量使树种在两个区间的重合部分

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#include<algorithm>
int n,h,ans;
int vis[100000];
struct node
{
    int begin;//区间左端点
    int end;//区间右端点
    int num;//区间内需要种树数量
}a[100000];

bool cmp(node x,node y)
{
    return x.end < y.end;
}

int main()
{
    scanf("%d%d",&n,&h);
    for(int i=0;i<n;i++)
        scanf("%d%d%d",&a[i].begin,&a[i].end,&a[i].num);
    sort(a,a+n,cmp);//根据区间的右端点排序
    memset(vis,0,sizeof(vis));//标记各点是否种过树,清零 
    for(int i=0;i<n;i++)
    {
        for(int j=a[i].begin;j>=a[i].end;j++)
        //从前往后看区域内有没有种树
        {
            if(!a[i].num)	break;//等于0直接跳出 
            if(vis[j] == 1)	a[i].num--;
        }
        for(int j=a[i].end;j>=a[i].begin;j--)
		//从后往前种树,保证与下一个区间的重合部分最大,使下一个区间需要种的树最少
      	{
            if(!a[i].num)	break;
            if(vis[j] == 0)//等于零就可以开始种 
            {
                vis[j] = 1;//种过树了标记为1 
                ans++;
                a[i].num--;//种完减一 
            }
        }
    }
    cout << ans << endl;
    return 0;
}

【贪心】排队接水
时间限制: 1 Sec 内存限制: 128 MB

有n个人在一个水龙头前排队接水,假如每个人接水的时间为Ti,请编程找出这n个人排队的一种顺序,使得n个人的平均等待时间最小。
输入
共两行,第一行为n;第二行分别表示第1个人到第n个人每人的接水时间T1,T2,…,Tn,每个数据之间有1个空格。
输出
有两行,第一行为一种排队顺序,即1到n的一种排列;第二行为这种排列方案下的平均等待时间(输出结果精确到小数点后两位)。
样例输入 Copy
10
56 12 1 99 1000 234 33 55 99 812
样例输出 Copy
3 2 7 8 1 4 9 6 10 5
291.90

思路:
例如甲乙丙丁戊5个人去水房打水,分别需要2、4、7、10、13分钟,若只有一个水龙头,想5人打水和等待的时间之和最短,则最短时间为多少?
5个人打水的总时间是不变的,而等待打水的时间受打水者的时间限制,只有打水者时间短,才能使等待时间短。所以让打水者速度从快到慢排队打水。甲先打2分钟,其他四人一共等待了2×4=8分钟,乙打水4分钟,剩下三人打水共等待了4×3=12分钟,丙打水7分钟,剩下两人打水共等待了7×2=14分钟,丁打水10分钟,最后一人等待10分钟,所以合计等待时间8+12+14+10=44分钟。则所求最短时间为36+44=80分钟。
定义一个sum来记录等待时间,sum += (n-i) * a[i]

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#include<algorithm>
struct node
{
	int x;//花费的时间 
	int y;//相应的序号 
}a[1005];

bool cmp(const node &a,const node &b)
{
	if(a.x == b.x)//时间相同,序号小的排在前面 
		return a.y < b.y;
	else
		return a.x < b.x;//否则按照花费时间从小到大排序 
}

int main()
{
	int n;	cin >> n;
	for(int i=1;i<=n;i++)
	{
		cin >> a[i].x;
		a[i].y = i;//给每个时间一个序号 
	}
	sort(a+1,a+1+n,cmp);
	double sum = 0.0;
	for(int i=1;i<=n;i++)
	{
		cout << a[i].y << " ";
		sum += (n-i) * a[i].x;
	}
	cout << endl;
	printf("%.2f\n",sum/n);
	return 0; 
} 

【贪心】线段
时间限制: 1 Sec 内存限制: 128 MB

题目描述
数轴上有n条线段,选取其中k条线段使得这k条线段两两没有重合部分,问k最大为多少。
输入
第一行为一个正整数n;
在接下来的n行中,每行有2个数ai,bi,描述每条线段。
输出
输出一个整数,为k的最大值。
样例输入 Copy
3
0 2
2 4
1 3
样例输出 Copy
2
提示
对于20%的数据,n≤10;
对于50%的数据,n≤103;
对于70%的数据,n≤105;
对于100%的数据,n≤106,0≤ai<bi≤106。

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#include<algorithm>
struct node
{
	int a;
	int b;
}s[1000000];

bool cmp(node x,node y)
{
	return x.b < y.b;
}

int main()
{
	int n;	scanf("%d",&n);
	for(int i=0;i<n;i++)
		scanf("%d%d",&s[i].a,&s[i].b);
	sort(s,s+n,cmp);
	int ans = 0;
	int k = 0;//数轴起始位置是0 
	for(int i=0;i<n;i++)
	{
		if(s[i].a >= k)
		{
			ans++;
			k = s[i].b;
		}
	}
	printf("%d\n",ans);
	return 0;
}

【贪心】家庭作业
时间限制: 1 Sec 内存限制: 128 MB

题目描述
老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10,要求在6天内交,那么要想拿到这10学分,就必须在第6天结束前交。
每个作业的完成时间都是只有一天。例如,假设有7次作业的学分和完成时间如下:

老师在开学第一天就把所有作业都布置了,每个作业如果在规定的时间内交上来的话才有学分。每个作业的截止日期和学分可能是不同的。例如如果一个作业学分为10,要求在6天内交,那么要想拿到这10学分,就必须在第6天结束前交。
每个作业的完成时间都是只有一天。例如,假设有7次作业的学分和完成时间如下:
输入
第一行一个整数N,表示作业的数量;
接下来N行,每行包括两个整数,第一个整数表示作业的完成期限,第二个数表示该作业的学分。
输出
输出一个整数表示可以获得的最大学分。保证答案不超过C/C++的int范围。
样例输入 Copy
7
1 6
1 7
3 2
3 1
2 4
2 5
6 1
样例输出 Copy
15
提示
对于20%的数据,N≤103;
对于40%的数据,N≤104;
对于60%的数据,N≤105;
对于100%的数据,N≤106,作业的完成期限均小于7×105

思路:
将作业按分数降序,同分按时限降序。
对每一天构造一个指针,初始时,i指向i-1,当安排第一个作业时,尽量靠后安排,因此在该作业时限之前找一个空闲的天安排上。同时更新指针,使得所有天的指针总是指向前面最靠近的空闲的天

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#include<algorithm>
struct node
{
    int score;
	int day;
}a[1010101];

bool cmp(node a,node b)
{
    if(a.score == b.score)
		return a.day > b.day;
    return a.score > b.score;
}

int n;
int pre[1010101];
bool vis[1010100];

int father(int day)
{
    if(!vis[day])
        return day;
    return pre[day] = father(pre[day]);
}

int main()
{
    scanf("%d",&n);
    for(int i=0;i<n;i++)
		scanf("%d%d",&a[i].day,&a[i].score);
    sort(a,a+n,cmp);
    for(int i=1;i<=700000;i++)
		pre[i] = i-1,vis[i] = false;
    int ans=0;
    for(int i=0;i<n;i++)
    {
        int ok = father(a[i].day);
        if(ok == 0)	continue;
        vis[ok] = true;
        ans += a[i].score;
    }
    printf("%d\n",ans);
}

【贪心】糖果传递
时间限制: 1 Sec 内存限制: 128 MB

题目描述
有n个小朋友坐成一圈,每人有ai个糖果。每人只能给左右两人传递糖果。每人每次传递一个糖果代价为1。
输入
第一行一个正整数nn<=1’000’000,表示小朋友的个数.
接下来n行,每行一个整数ai,表示第i个小朋友得到的糖果的颗数.
输出
求使所有人获得均等糖果的最小代价。
样例输入 Copy
4
1
2
5
4
样例输出 Copy
4

思路:
首先,最终每个小朋友的糖果数量可以计算出来,等于糖果总数除以n,用ave表示
假设标号为i的小朋友开始有Ai颗糖果,Xi表示第i个小朋友给了第i-1个小朋友Xi颗糖果,如果Xi<0,说明第i-1个小朋友给了第i个小朋友Xi颗糖果,X1表示第一个小朋友给第n个小朋友的糖果数量。 所以最后的答案就是ans=|X1| + |X2| + |X3| + ……+ |Xn|。
对于第一个小朋友,他给了第n个小朋友X1颗糖果,还剩A1-X1颗糖果;但因为第2个小朋友给了他X2颗糖果,所以最后还剩A1-X1+X2颗糖果。根据题意,最后的糖果数量等于ave,即得到了一个方程:A1-X1+X2=ave。
同理,对于第2个小朋友,有A2-X2+X3=ave。最终,我们可以得到n个方程,一共有n个变量,但是因为从前n-1个方程可以推导出最后一个方程,所以实际上只有n-1个方程是有用的。
尽管无法直接解出答案,但可以用X1表示出其他的Xi,那么本题就变成了单变量的极值问题。
对于第1个小朋友,A1-X1+X2=ave -> X2=ave-A1+X1 = X1-C1(假设C1=A1-ave,下面类似)
对于第2个小朋友,A2-X2+X3=ave -> X3=ave-A2+X2=2ave-A1-A2+X1=X1-C2
对于第3个小朋友,A3-X3+X4=ave -> X4=ave-A3+X3=3ave-A1-A2-A3+X1=X1-C3
……
对于第n个小朋友,An-Xn+X1=ave。
我们希望Xi的绝对值之和尽量小,即|X1| + |X1-C1| + |X1-C2| + ……+ |X1-Cn-1|要尽量小。注意到|X1-Ci|的几何意义是数轴上的点X1到Ci的距离,所以问题变成了:给定数轴上的n个点,找出一个到他们的距离之和尽量小的点,而这个点就是这些数中的中位数

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#include<algorithm>
int a[1000005],c[1000005];
int main()
{
	int n;
	ll sum=0;
	ll ans=0;
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		sum += a[i];
	}	
	sum = sum/n;
	for(int i=1;i<=n;i++)
	{
		c[i] = c[i-1]+a[i]-sum;
	}
	sort(c+1,c+n+1);
	int mid = c[(n+1)/2];
	for(int i=1;i<=n;i++)
		ans += abs(c[i]-mid);
	printf("%lld\n",ans);
	return 0;
}

【贪心】钓鱼II
时间限制: 1 Sec 内存限制: 128 MB

题目描述
在一条水平路边,有n个钓鱼湖,从左到右编号为1,2,…,n。佳佳有H个小时的空余时间,他希望利用这个时间钓到更多的鱼。他从1出发,向右走,有选择的在一些湖边停留一定的时间(是5分钟的倍数)钓鱼。最后在某一个湖边结束钓鱼。佳佳从第i个湖到第i+1个湖需要走5×Ti分钟路,还测出在第i个湖停留,第一个5分钟可以钓到Fi条鱼,以后每再钓5分钟,可以钓到的鱼量减少Di,若减少后的鱼量小于0,则减少后的鱼量为0。为了简化问题,佳佳假定没有其他人钓鱼,也没有其他因素影响他钓到期望数量的鱼。请编程求出佳佳最多能钓鱼的数量。
输入
第一行一个整数n(2≤n≤100),表示湖的个数
第二行一个整数H(1≤H≤20),表示佳佳的空闲时间
第三行有n个整数,依次表示每个湖第一个5分钟能钓到鱼的数量
第四行有n个整数,依次表示以后的每5分钟钓鱼数量比前一个5分钟钓鱼数量减少的数量
第五行有n−1个整数,Ti表示由第i个湖到第i+1个湖需要花5×Ti分钟的路程
输出
输出只有一行,表示佳佳最多能钓鱼的数量。
样例输入 Copy
3
1
4 5 6
1 2 1
1 2
样例输出 Copy
35
提示
在第1个湖钓15分钟,共钓得4+3+2=9条鱼;
在第2个湖钓10分钟,共钓得5+3=8条鱼;
在第3个湖钓20分钟,共钓得6+5+4+3=18条鱼;
从第1个湖到第2个湖,从第2个湖到第3个湖,共用时间15分钟,共得35条鱼,并且这是最多的数量。

思路:
题目中说了某些湖,我们就要枚举每一个湖作为结束点,然后用总时间减去走路的时间除以5就会得到能钓鱼的次数,记为sum
此题就是让我们从中选择sum个最大的数。
假设我们在第i个湖中选了x个数,在j个湖中选了y个数,就相当于我们在第i个湖中钓了x次鱼,在第j个湖中钓了y次鱼了
因为d【i】>=0,所以所有数列呈递减排序,于是如果我们要选择某一个数列的第i个数,这个数列的前i-1个数都已经被选了(因为比第i个数大),所以是符合题意的,本题用优先队列来做

代码:

//贪心
#include<bits/stdc++.h>
using namespace std;
#include<iostream>
#include<algorithm>
struct Node
{
	int Num,bl;//bl表示变量,即每过五分钟减少的钓鱼量
	bool operator<(const Node &a) const
	{
		return a.Num>Num;
	}
};
priority_queue<Node> q;
int n,h;
int f[110];
int d[110];
int t[110];
int ans;
int sum;
int m,Sum;
int main()
{
	Node temp;
	scanf("%d",&n);
	scanf("%d",&h);
	h*=60;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&f[i]);
	}
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&d[i]);
	}
	for(int i=1;i<n;i++)
	{
		scanf("%d",&t[i]);
		t[i]*=5;
	}
	for(int i=1;i<=n;i++)
	{
		Sum+=t[i-1];
		m=h-Sum;
		m/=5;
		sum=0;
		for(int j=1;j<=i;j++)
		{
			temp.Num=f[j];
			temp.bl=d[j];
			q.push(temp);
		}
		while(m>0&&q.top().Num>0)//注意m可能小于0
		{
			sum+=q.top().Num;
			temp.Num=q.top().Num-q.top().bl;
			temp.bl=q.top().bl;
			q.pop();
			q.push(temp);
			m--;
		}
		ans=max(ans,sum);
	}
	printf("%d",ans);
	return 0;
}
发布了54 篇原创文章 · 获赞 0 · 访问量 1161

猜你喜欢

转载自blog.csdn.net/magic_wenge/article/details/104510692
UPC