贪心算法

贪心算法

头大的一天呢!好多都没有学到,勉勉强强搞懂,有待强化!加油!
在这里插入图片描述

一、圣诞老人的礼物
总时间限制: 1000ms 内存限制: 65536kB
描述
圣诞节来临了,在城市A中圣诞老人准备分发糖果,现在有多箱不同的糖果,每箱糖果有自己的价值和重量,每箱糖果都可以拆分成任意散装组合带走。圣诞老人的驯鹿最多只能承受一定重量的糖果,请问圣诞老人最多能带走多大价值的糖果。

输入
第一行由两个部分组成,分别为糖果箱数正整数n(1 <= n <= 100),驯鹿能承受的最大重量正整数w(0 < w < 10000),两个数用空格隔开。其余n行每行对应一箱糖果,由两部分组成,分别为一箱糖果的价值正整数v和重量正整数w,中间用空格隔开。
输出
输出圣诞老人能带走的糖果的最大总价值,保留1位小数。输出为一行,以换行符结束。
样例输入
4 15
100 4
412 8
266 7
591 2
样例输出
1193.0

优先挑选价值重量比大的礼物。
按价值/重量比
从大到小依次选取礼物,对选取的礼物尽可能的多地装,直到总重量达到W
复杂度O(nlogn)

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

const double eps=1e-6;
struct candy
{
    int v;
    int w;
    bool operator<(const candy &c)//按照价值重量比,如果价值重量比大,就在前面
    {
        return double(v)/w-double (c.v)/c.w>eps;
    }
}candies[110];
int main()
{
    int n,w;
    scanf("%d%d",&n,&w);
    for(int i=0;i<n;i++)
    scanf("%d%d",&candies[i].v,&candies[i].w);
    sort(candies,candies+n);
    int totalw=0;
    double totalv=0;
    for(int i=0;i<n;i++)
        if(totalw+candies[i].w<=w)//遍历数组
    {
        totalw+=candies[i].w;
        totalv+=candies[i].v;
    }
    else {totalv+=candies[i].v*double(w-totalw)/candies[i].w;
    break;}
    printf("%.1f",totalv);
    return 0;
}

贪心算法
每一步行动总是按照某种指标选取最优的操作,来进行,该指标只看眼前,并不考虑以后可能会造成的影响。

贪心算法需要证明其正确性。

“圣诞老人礼物”题,若糖果只能正箱拿,则贪心法错误。
我就只看这个价值比最大我就拿哪一个,完全不考虑对后续有什么影响,所以用贪心法要证明他的正确性。

二、电影节
总时间限制: 1000ms 内存限制: 65536kB
描述
大学生电影节在北大举办! 这天,在北大各地放了多部电影,给定每部电影的放映时间区间,区间重叠的电影不可能同时看(端点可以重合),问李雷最多可以看多少部电影。

输入
多组数据。每组数据开头是n(n<=100),表示共n场电影。
接下来n行,每行两个整数(0到1000之间),表示一场电影的放映区间
n=0则数据结束
输出
对每组数据输出最多能看几部电影
样例输入
8
3 4
0 7
3 8
15 19
15 20
10 15
8 18
6 12
0
样例输出
3

思路:
所有的电影按照结束时间从小到大排序,第一步选结束时间最早的那部电影。然后都选和上一部选中的电影不冲突且结束时间最早的电影,暂时先顾眼前,但是否成立还是要证明的。
复杂度:O(nlogn)

可利用替代法来证明是否可以用贪心算法。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;

int n;
const int eps=1e-6;

struct film
{
    int s;
    int e;
    bool operator<(film &f)
   {
        return double(e)-double(f.e)>eps;
   }
} film[100];
int main()
{
    while(cin>>n&&n)
    {
        for(int i=0; i<n; i++)
            cin>>film[i].s>>film[i].e;
        sort(film,film+n);
        int num=1;
        int pre=film[n-1].e;
        for(int i=n-2; i>=0; i--)
        {
            if(film[i].s>=pre)
            {
                num++;
                pre=film[i].e;
            }
        }
        cout<<num<<endl;
    }
}

类似圣诞老人改编。

三、stall reservations
分配畜栏

贪心解法:
所有的奶牛都必须挤奶。到了一个奶牛的挤奶开始时间,就必须为这个奶牛找畜栏。因此按照奶牛的开始时间诸葛处理他们,是必然的。畜栏的结束时间,就是正在其里面挤奶的奶牛的结束时间。同一个畜栏的结束时间是不断在变的。
复杂度:O(nlogn)

需要用优先队列存放已经分配的畜栏,并使得结束时间最早的畜栏始终位于队列的头部。
由于按开始时的顺序处理奶牛是必然的。且按照该算法,为奶牛i分配新的畜栏确实是不得不分配的,所以算法正确。

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<vector>
using namespace std;

struct cow
{
    int a,b;//挤奶区间起终点
    int No;//编号
    bool operator<(const cow &c)//这就规定了一个规则,谁的挤奶时间开始的比较小,谁就排在前面
    const{return a<c.a;}
} cows[50100];

int pos[50100];//pos[i]表示编号为i的奶牛去的畜栏的编号

struct Stall
{
    int end;//结束时间
    int No;//编号
    bool operator<(const Stal &s)//这个是c++的知识啦!
    const{return end>s.end;}
    Stall(int e,int n):end(e),No(n) {}
};
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=0; i<n; ++i)
    {
        scanf("%d%d",&cows[i].a,&cows[i].b);
        cows[i].No=i;
    }
    sort(cows,cows+n);
    int total =0;//畜栏的总数
    priority_queue<Stall>pq;//优先队列,放的是畜栏
    for(int i=0;i<n;++i)//依次处理所有的奶牛
    {
        if(pq.empty())//只有i=0的时候,队列才为空
        {
            ++total;
            pq.push(Stall(cows[i].b,total));
            pos[cows[i].No]=total;
        }
        else {
            Stall st=pq.top();
            if(st.end<cows[i].a)
            {//端点也不能重合
                pq.pop();//O(logn)
                pos[cows[i].No]=st.No;
                pq.push(Stall(cows[i].b,st.No));//O(logn)
            }
            else {//对应if(st.end<cows[i].a),没找到空的畜栏              
            ++total;
            pq.push(Stall{cows[i].b,total});
            pos[cows[i].No]=total;
            }
        }
        printf("%d\n",total);
        for(int i=0;i<n;i++)
            printf("%d\n",pos[i]);
        return 0;
    }
}


四、Rader Installation
放置导弹

总时间限制: 1000ms 内存限制: 65536kB
描述
Assume the coasting is an infinite straight line. Land is in one side of coasting, sea in the other. Each small island is a point locating in the sea side. And any radar installation, locating on the coasting, can only cover d distance, so an island in the sea can be covered by a radius installation, if the distance between them is at most d.

We use Cartesian coordinate system, defining the coasting is the x-axis. The sea side is above x-axis, and the land side below. Given the position of each island in the sea, and given the distance of the coverage of the radar installation, your task is to write a program to find the minimal number of radar installations to cover all the islands. Note that the position of an island is represented by its x-y coordinates.
在这里插入图片描述

Figure A Sample Input of Radar Installations
输入
The input consists of several test cases. The first line of each case contains two integers n (1<=n<=1000) and d, where n is the number of islands in the sea and d is the distance of coverage of the radar installation. This is followed by n lines each containing two integers representing the coordinate of the position of each island. Then a blank line follows to separate the cases.

The input is terminated by a line containing pair of zeros
输出
For each test case output one line consisting of the test case number followed by the minimal number of radar installations needed. “-1” installation means no solution for that case.
样例输入
3 2
1 2
-3 1
2 1

1 2
0 2

0 0
样例输出
Case 1: 2
Case 2: 1

对每个岛屿p,可以算出,覆盖他的雷达,必须位于x轴上的区间[ps,pe]。
如果有雷达位于某个x轴区间[a,b],则称雷达覆盖此区间。为题转换为,至少要在x轴上放几个雷达(点),才覆盖全部区间[p1s,p1e],[p2s,p2e]…[pns,pne]

重要结论:只挑区间起点来放置雷达
如果可以找到一个雷达同时覆盖多个区间,那么把多个区间按起点坐标从小到大排序,则最后一个区间(起点最靠右)k的起点,就能覆盖所有区间

贪心算法:
(1)将所有区间按照起点从小到大排序,并编号0-(n-1)
(2)依次考察每个区间的起点,看要不要在那里放雷达。开始,所有区间都没被覆盖,所以目前编号最小的未被覆盖的区间编号FirstNoCovered=0

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<queue>
#include<cmath>
using namespace std;

const double eps=1e-6;
int n,d;
struct place
{
    int x;
    int y;
    double l;
    double r;
    bool operator<(const place &k) const
    {
        if(r != k.r) return r < k.r;
        else return l < k.l; 
    }
} p[1010];

int main()
{
    int t=1;
    while(cin>>n>>d&&(n||d))
    {
        int ans=1,ym=0;
        for(int i=0; i<n; i++)
        {
            cin>>p[i].x>>p[i].y;
            ym = max(abs(p[i].y), ym);
//            ym=fabs(p[i].y)>ym?fabs(p[i].y):ym;
        }
        if(d<ym)
        {
          cout<<"Case "<<t++<<": -1"<<endl;
          continue;
        }
        if(n==1)
        {
            cout<<"Case "<<t++<<": 1"<<endl;
            continue;
        }
        for(int i=0;i<n;i++)
        {
            p[i].l=double(-(sqrt(pow(d,2)-pow(p[i].y,2))))+p[i].x;
            p[i].r=double(sqrt(pow(d,2)-pow(p[i].y,2)))+p[i].x;
    	}
	    sort(p,p+n);
	    int g=0;
	  	for(int i=1; i<n; i++) {
	  		if(p[i].l <= p[g].r) continue;
	  		g = i, ans++;
		}
	    cout<<"Case "<<t++<<": "<<ans<<endl;
	}
	return 0;
}

五、钓鱼
Gone Fishing
总时间限制: 2000ms 内存限制: 65536kB
描述
John is going on a fishing trip. He has h hours available (1 <= h <= 16), and there are n lakes in the area (2 <= n <= 25) all reachable along a single, one-way road. John starts at lake 1, but he can finish at any lake he wants. He can only travel from one lake to the next one, but he does not have to stop at any lake unless he wishes to. For each i = 1,…,n - 1, the number of 5-minute intervals it takes to travel from lake i to lake i + 1 is denoted ti (0 < ti <=192). For example, t3 = 4 means that it takes 20 minutes to travel from lake 3 to lake 4. To help plan his fishing trip, John has gathered some information about the lakes. For each lake i, the number of fish expected to be caught in the initial 5 minutes, denoted fi( fi >= 0 ), is known. Each 5 minutes of fishing decreases the number of fish expected to be caught in the next 5-minute interval by a constant rate of di (di >= 0). If the number of fish expected to be caught in an interval is less than or equal to di , there will be no more fish left in the lake in the next interval. To simplify the planning, John assumes that no one else will be fishing at the lakes to affect the number of fish he expects to catch.
Write a program to help John plan his fishing trip to maximize the number of fish expected to be caught. The number of minutes spent at each lake must be a multiple of 5.
输入
You will be given a number of cases in the input. Each case starts with a line containing n. This is followed by a line containing h. Next, there is a line of n integers specifying fi (1 <= i <=n), then a line of n integers di (1 <=i <=n), and finally, a line of n - 1 integers ti (1 <=i <=n - 1). Input is terminated by a case in which n = 0.
输出
For each test case, print the number of minutes spent at each lake, separated by commas, for the plan achieving the maximum number of fish expected to be caught (you should print the entire plan on one line even if it exceeds 80 characters). This is followed by a line containing the number of fish expected.
If multiple plans exist, choose the one that spends as long as possible at lake 1, even if no fish are expected to be caught in some intervals. If there is still a tie, choose the one that spends as long as possible at lake 2, and so on. Insert a blank line between cases.
样例输入
2 //n个湖泊
1 //所拥有的时间
10 1 //最初的5分钟所可捕到的🐟
2 5 //每个湖减少的速率
2 //从一个湖到另一个湖的时间
4
4
10 15 20 17
0 3 4 3
1 2 3
4
4
10 15 50 30
0 3 4 3
1 2 3
0
样例输出
45, 5
Number of fish expected: 31

240, 0, 0, 0
Number of fish expected: 480

115, 10, 50, 35
Number of fish expected: 724

难点:走路的时间可多可少,不知道到底该花多长时间纯钓鱼才合适(可能有好湖在最右边)
解决:枚举最终停下来的湖,将方案分成n类。每类方案的走路时间就是确定的,在每类方案中找最优解,然后再优中选优。
贪心:在确定停下来的湖是x的情况下,假定纯钓鱼的时间是k个时间片,用三元组(F,i,j)(1<=i<=x,1<=j<=k)表示湖i的第j个时间片能够钓到的鱼的数目是F,将所有的(F,i,j)(共x*k个),按F的大小选前k个,就构成了最佳钓鱼方案

#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;

const int N=25;
int n,h;
int f[N],d[N],t[N];//f第一个五分钟钓的鱼量,d为每个五分钟减少的鱼量,t为i到i+1五分钟的个数
int ans;
int each[N];//记录最终每条湖用的时间
int tans,teach[N];//最优钓鱼量和各湖钓鱼时间
int th,tf[N];//有效钓鱼时间和每条湖前五分钟的钓鱼量

int main()
{
	int i,j;
	while(cin>>n&&n>0){//当湖的数量为0的时候结束
		cin>>h;//输入时间
		for(i=0;i<n;i++){
			cin>>f[i];//第一次的鱼量
		}
		for(i=0;i<n;i++){
			cin>>d[i];//每五分钟减少的鱼量
		}
		for(i=0;i<n-1;i++){
			cin>>t[i];//每个湖间距离需要的时间片
		}
		h*=12;//一小时12个时间片
		ans=-1;
		for(i=0;i<n;i++){//表示再第i条湖停下来
			//初始化每一次贪心
			th=h;//有效时间先初始化为总时间
			for(j=0;j<n;j++){
				tf[j]=f[j];//每条湖初始的钓鱼量初始为第一次五分钟的钓鱼量
				teach[j]=0;//每个湖的钓鱼时间初始化为0
			}
			tans=0;//最大钓鱼数初始化为0

			//对每五分钟贪心选择钓鱼量最大的湖钓鱼
			while(th>0){//当有效时间大于0
				int ind=0,max=tf[0];//令第一条湖的鱼量为最大值 ,ind标记湖是第几条湖
				for(j=0;j<=i;j++){
					if(tf[j]>max){//不考虑顺序先找第一次鱼量最大的湖
						max=tf[j];
						ind=j;
					}
				}
				if(max==0){//最大钓鱼量为0时,将剩余的钓鱼时间加到第一个湖上的钓鱼时间
					teach[0]+=th*5;//例如样例一
					break;
				}
				else{
					teach[ind]+=5;//最大湖的钓鱼时间,每钓一次加一次五
					tans+=tf[ind];//加上最大鱼量的湖的该次的鱼数
					if(tf[ind]>=d[ind])//如果鱼量不少于减少的鱼数 ,则减
					{
						tf[ind]-=d[ind];
					}
					else{
						tf[ind]=0;//小于减少数则赋值为0
					}
				}
				th--;//有效时间减少一个时间片(一个时间片五分钟)
			}
			if(i!=n-1){//i的话是表示在第i条湖停下来
				h-=t[i];//减去到下一条湖的时间片
			}
			if(tans>ans){//如果值大于前面的值,就把值赋给ans
				ans=tans;
				for(j=0;j<n;j++){
					each[j]=teach[j];//记录最终每条湖用的时间
				}
			}
		}
		cout<<each[0];
		for(i=1;i<n;i++){
			cout<<", "<<each[i];
		}
		cout<<endl;
		cout<<"Number of fish expected: "<<ans<<endl;
		cout<<endl;
	}
	return 0;
}

2021.1.27-1.29

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值