三道类似的简单贪心

这几天遇到三道相似的贪心问题。

1. 汽车加油问题(算法设计与分析基础 习题4-9)

  初始时油量为n。从起点到终点之间有k个加油站,汽车油箱容量上限为n,每个加油站可无限量供应汽油

  给出n,k和相对位置(在一条直线上),求最少加油次数及对应加油记录。

  贪心策略:一直走,当到不了站点 i 时,在i-1加油至容量上限n(距离超过n时无解)。

 1 #include <cstdio>
 2 #include <cstring>
 3 using namespace std;
 4 const int MAX_N=100;
 5 int vis[MAX_N];
 6
 7 int greedy(int n,int k,int* dis)
 8 {
 9     memset(vis,0,sizeof(vis));
10     int ans=0;
11     int cur_petrol=0;
12     for(int i=0;i<=k;i++)//遍历从第一个加油站到终点
13     {
14         cur_petrol-=dis[i];//到达此点后的剩余油量
15         if(cur_petrol<0)//需要在上一点加油了
16         {
17             cur_petrol=n-dis[i];//在上一点加满油后到达这一点后的剩余油量
18             if(cur_petrol<0) return -1;//距离超过油箱容量,无解
19             vis[i]=1;
20             ans++;
21         }
22     }
23     return ans;
24 }
25
26 void print_greedy(int k)
27 {
28     for(int i=1;i<=k;i++)//在0号点(起点)加油不计入
29     {
30         if(vis[i]) printf("%d ", i);
31     }
32     printf("\n");
33     return ;
34 }
35
36 int main()
37 {
38     freopen("add_petrol.txt","r",stdin);
39     int n,k;
40     int dis[MAX_N];
41     scanf("%d%d",&n,&k);
42     for(int i=0;i<=k;i++)
43         scanf("%d",&dis[i]);//dis[k]表示第k个驿站到第k+1个的距离
44     int ans=greedy(n,k,dis);
45     if(ans==-1) printf("no solution\n");
46     else print_greedy(k);
47     return 0;
48 }

add_petrol.cpp

  贪心策略证明思路:最优值唯一,任意最优解可通过交换元素(保证能够到达终点)改造为贪心选择策略得到的解,其值仍为最优值。(Exchange arguments)

 

2. Expedition(POJ 2431)

  初始时油量为P。从起点到终点之间有k个加油站,汽车油箱容量无上限,每个加油站i能供应的汽油量有上限fi

  给出P,k,相对位置和f数组,求最少的加油次数。

  换个角度看:在到达加油站 i 时,就获得了一次在之后任何时候都可以加fi单位汽油的机会。(来自《挑战程序设计竞赛》)

  贪心策略:一直走,当到不了站点 i 时,选 i 之前没有加过油的、fj最大的站点j,加上fj量的汽油。(距离超过i之前的全部fj之和时无解)。

  为了快速选出前i个加油站fi最大的那个,可用堆来维护。因为上一个问题每个站点是无限量供应汽油,且每次加油的上限量都是相同的,所以不用选择。

 1 #include <cstdio>
 2 #include <queue>
 3 #include <algorithm>
 4 using namespace std;
 5 int n,L,P;
 6 struct Stop
 7 {
 8     int dis,fuel;
 9 }stops[10002];
10
11 bool mycmp(const Stop &a,const Stop &b)
12 {
13     return a.dis<=b.dis;
14 }
15
16 int main()
17 {
18     freopen("2431.txt","r",stdin);
19     scanf("%d",&n);
20     for(int i=1;i<=n;i++)
21         scanf("%d%d",&stops[i].dis,&stops[i].fuel);
22     scanf("%d%d",&L,&P);
23     for(int i=1;i<=n;i++)
24         stops[i].dis=L-stops[i].dis;
25     stops[n+1].dis=L;
26     stops[n+1].fuel=0;
27     stops[0].dis=0;
28     sort(stops+1,stops+1+n+1,mycmp);//按位置排序
29
30     priority_queue<int> q;
31     int cur_fuel=P,cnt=0,flag=0;
32     for(int i=1;i<=n;i++)
33     {
34         cur_fuel-=stops[i].dis-stops[i-1].dis;//到达此点后剩余的油量
35         while(cur_fuel<0)//需要在之前加油才能到这一点
36         {
37             if(q.empty()) {flag=1; break;}//当前i个点都被加过了,无解
38             cur_fuel+=q.top();
39             q.pop();
40             cnt++;
41         }
42         q.push(stops[i].fuel);
43     }
44     if(flag) printf("-1\n");
45     else printf("%d\n",cnt);
46     return 0;
47 }

2431.cpp

  贪心策略证明思路:最优值唯一,贪心选择策略得到的解至少能达到和其他最优解一样的效果(能够到达终点),其值仍为最优值。(Staying ahead)

 

3. Duff and Meat(CF588A(#326div2A))

  要想愉快地度过第i天,需要吃掉ai kg的肉;当天肉的售价为$pi/kg,无限量供应。要求保持连续n天每天都能吃到ai kg的肉(可以吃之前买来储存的,永远不会过期。。。相当于储存容量无上限)。

  给出n和a,p数组,求最少的买肉花费。

  参照上一题,这道同样可以换个角度看:在到达第i天时,就获得了在之后任何时候都可以以这一天的售价无限量地买肉的机会。

    贪心策略:每遇到一个价格更小的值,一直在这里买,直到遇到下一个更小的值。

 1 #include <cstdio>
 2 using namespace std;
 3 const int MAX_N=100005;
 4 int n;
 5 int a[MAX_N],p[MAX_N];
 6
 7 int main()
 8 {
 9     scanf("%d",&n);
10     for(int i=0;i<n;i++)
11         scanf("%d%d",&a[i],&p[i]);
12     int minn=p[0];
13     int ans=minn*a[0];
14     for(int i=1;i<n;i++)
15     {//每遇到一个价格更小的值,一直在这里买,直到遇到下一个更小的值为止
16         if(p[i]<minn) minn=p[i];
17         ans+=a[i]*minn;
18     }
19     printf("%d\n", ans);
20     return 0;
21 }

588a.cpp

  这道题的背景本质上和前两道相同,只是由于容量和供应量都无上限,求最少购买次数没意义,所以增加了一个价格,求总花费的最小值。

  贪心策略证明思路:最优值唯一,当没有重复的售价时,最优解也是唯一的。假设存在比贪心策略更小的花费,那么有第 i 天是用比前 i 天的最低价格还要低的价格买到的,而不存在这样的价格,所以不存在更小的花费。

  如果容量和供应量都有上限,问题会更复杂,也许贪心思想不再适用,待见到了再来更新吧

时间: 2024-09-20 03:00:09

三道类似的简单贪心的相关文章

为Windows应用创建简单的异步调用模式

简介 最近我编写了很多智能客户端应用,总结了一些能够使应用程序在后台调用Web Service时不冻结前台界面的异步调用方法.虽然当前.NET Framework本身已经提供了异步调 用的机制,但我发现在Windows应用中这一机制比较难于把握,因为这时你需要正确的控制用 户界面线程处理. 在这篇文章中,我将教给您一种在Windows应用程序中实现异步调 用Web服务的简单方法,通过这一方法,您不用再考虑后台线程与前台界面线程的交互关系了 . 服务代理 Visual Studio .NET会生成

UVa 311 Packets (贪心)

311 - Packets Time limit: 3.000 seconds http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=113&page=show_problem&problem=247 A factory produces products packed in square packets of the same height h and of the si

iOS流布局UICollectionView系列一——初识与简单使用UICollectionView

iOS流布局UICollectionView系列一--初识与简单使用UICollectionView 一.简介         UICollectionView是iOS6之后引入的一个新的UI控件,它和UITableView有着诸多的相似之处,其中许多代理方法都十分类似.简单来说,UICollectionView是比UITbleView更加强大的一个UI控件,有如下几个方面: 1.支持水平和垂直两种方向的布局 2.通过layout配置方式进行布局 3.类似于TableView中的cell特性外,

js错误处理与调试理论和办法

                                                                                                                                        阅读本文,以抓取有用的信息(可以以我加粗为参考)为主,老外写的 废话较多 ECMA-262 第 3 版引入了 try-catch 语句,作为 JavaScript 中处理异常的一种标准方式.基本的语 法如下所示,显而易见,这与

ASP.NET 2.0 和数据绑定控件:新的角度,新的做法

asp.net|控件|数据 适用于:Microsoft ASP.NET 1.xMicrosoft ASP.NET 2.0 摘要:了解 ASP.NET 2.0 中的用于生成自定义数据绑定控件的工具是如何演变的.   本页内容 为什么需要新的数据源模型  ASP.NET 2.0 中的数据绑定控件  分析要点  数据绑定机制   列表控件  HeadlineList 示例控件  管理自定义集合  关于复合控件的一点讨论  小结 为什么需要新的数据源模型数据绑定是开发人员在 ASP.NET 1.x 中发

微软.NET平台中类型使用的基本原理

微软 微软.NET平台中类型使用的基本原理 ----微软 .NET平台系列文章之二 译文/赵湘宁 在上一次的讨论中,我介绍了许多微软.NET平台公共语言运行时CLR (common language runtime) 中与类型有关的基本概念.其中重点讨论了如何从System.Object类型中派生出所有别的类型,以及程序员能够使用的多种强制类型转换机制(如C#操作符).最后,我提到了编译器如何使用名字空间以及公共语言运行时CLR是如何忽略名字空间的. 在本文中,我们将继续上次类型基础的讨论.首先

电子邮箱格式怎么写

电子邮箱格式怎么写,不少开始接触邮件的朋友经常问这样的问题,其实写邮件很简单,现在用的最多的是网易163邮箱和QQ邮箱.新浪邮箱,下面做下演示操作,教你怎么写电子邮箱格式.电子邮箱的格式通常为:username@domain.com.其中username为用户名(邮箱帐户名),"@"后面的是域名.如腾讯的邮箱格式一般为:xxxx@qq.com(xxxx为QQ号码).电子邮箱格式中的@符号是同时按shift+数字键 2打出来的.刚用电脑的朋友可能一下不知道.下面本文中就简单的说下网易16

电子邮箱格式怎么写 电子邮箱格式

电子邮箱格式怎么写,不少开始接触邮件的朋友经常问这样的问题,其实写邮件很简单,现在用的最多的是网易163邮箱和QQ邮箱.新浪邮箱,下面做下演示操作,教你怎么写电子邮箱格式.电子邮箱的格式通常为:username@domain.com.其中username为用户名(邮箱帐户名),"@"后面的是域名.如腾讯的邮箱格式一般为:xxxx@qq.com(xxxx为QQ号码).电子邮箱格式中的@符号是同时按shift+数字键 2打出来的.刚用电脑的朋友可能一下不知道.下面本文中就简单的说下网易16

TDD的iOS开发初步以及Kiwi使用入门

测试驱动开发(Test Driven Development,以下简称TDD)是保证代码质量的不二法则,也是先进程序开发的共识.Apple一直致力于在iOS开发中集成更加方便和可用的测试,在Xcode 5中,新的IDE和SDK引入了XCTest来替代原来的SenTestingKit,并且取消了新建工程时的"包括单元测试"的可选项(同样待遇的还有使用ARC的可选项).新工程将自动包含测试的target,并且相关框架也搭建完毕,可以说测试终于摆脱了iOS开发中"二等公民"