贪心算法的应用实例
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
最大收益=40+50+30+30
【算法分析】 本题转化成模型就是:在一个无向图中,对于每个点,取一条和它相关联的边(如果这 样的边存在的话) ,使得取出来的所有边的权和最大。 首先,如果这个图是不连通的,那么它的各个连通分量之间是没有任何联系的。对这些 连通分量中的问题可以分别独立地解决, 合并起来就是整个问题的解。 所以我们在下面的讨 论中假定图是连通的。 直观地考虑, 如果图中存在度为 1 的点, 那么就把这一点上的唯一的一条边分配给这个 点(将某条边“分配”给某个点的含义是:将这条边作为和这一点相关联的边取出来,同时 这一点就失效了,因为和它相关联的其他边都不能再取了) 。如果不存在这样的点,那么此 时有两种情况: 一种是边数等于点数, 那么这个图就是一个环, 这时可以取出图中所有的边; 一种是边数大于点数, 那么就可以把这个图中权最小的一条边直接删去, 因为这条边 “显然” 不会被取到的。 依据这样一个直观思想,本题可以用贪心法来解决。 贪心算法(用于连通图) : 1、如果图中只有一个点,直接结束算法。 2、如果图中存在度为 1 的点,执行 3;否则转 4。 3、任意找一个度为 1 的点 v,将 v 上的唯一一条边分配给它。转 2。 4、如果图中的边数等于点数,执行 5;否则转 6。 5、设图中的点数(也就是边数)为 n。任取一条边 e1,将它分配给它的两个端点中的任意
在任意两个城市之间,这样的交易只能进行一次。因为你第二次贩运你的商品时,人们 对它们就不会感兴趣了。 现在你只身来到这个大陆上, 用有限的资金在每个城市中购买了一支商队。 你需要想办 法让你的这 N 支商队给你带来最大的经济收益。
3
任务说明 给出这个大陆的地图和每两个城市之间的贸易值 (如果这两个城市之间有路可通的话) , 你需要指挥你的 N 支商队进行一次经商,使得这 N 支商队在这次经商中获得的总收益最大。 注意: 你的每支商队只能进行一次交易, 即它们只能从它们所在的城市到达一个相邻的城市。 当然,它们也可以不进行任何交易。 输入数据 输入文件的第一行有两个整数 N(1 N 100) 、M(M 0) ,分别表示这个大陆上的 城市数和道路数。 接下来有 M 行,每行包括三个整数 i、j(1 i,j N 且 i j) 、v(1 V 10000), 表示一条道路的信息。其中 i 和 j 表示这条路在城市 i 和城市 j 之间,v 表示沿着这条路进 行一次交易所得的收益。i 和 j 的顺序是无关的,并且任意两个城市之间最多存在一条路。 输出数据 你的输出文件应该 2 行, 第 1 行包含 N 个整数。 其中第 k 个整数表示你在城市 k 中的商 队将要前往哪个城市进行交易(如果这支商队进行交易的话)或者为 0(如果这支商队不进 行任何交易) 。第 2 行输出最大收益值。 输入输出样例 input.in 4 1 1 2 2 3 5 2 3 3 4 4 40 30 50 30 20 output.out 2 3 1 2 150 样例图示
例 6.数字游戏 【题目描述】 小 W 发明了一个游戏,他在黑板上写出一行数字 a1,a2,…an,然后给你 m 个回合的机 会,每个回合你可以从中选一个数擦除它,接着剩下来的每个数字 ai 都要递减一个值 bi。 如此重复 m 个回合,所有你擦除的数字之和就是你得到的分数。 编程帮小 W 算算,对于每个给出的 an 和 bn 序列,可以得到的最大得分是多少? 数据输入: 由文件 game. in 提供输入数据。文件的第 1 行一个整数 n(1≤n≤200) ,表示数字的 个数;第二行一个整数 m(1≤m≤n) ,表示回合数;接下来一行有 n 个不超过 10000 的正整 数,a1,a2,…an,表示原始数字;最后一行有 n 个不超过 500 的正整数,b1,b2,…bn, 表示每回合每个数字递减的值。 结果输出: 程序运行结束时,将计算结果输出到文件 game. out 中。一个整数,表示最大可能的 得分。 输入文件示例 输入: 3 3 10 20 30 4 5 6 输出: 47 【算法分析】 本题上面一排数是作为被减数的,若对被减数采用贪心算法不一定能得到全局最优 解。因为被减数小减数大,其差小会导致最大得分少。先运用贪心的思想对第二排减数进行 从大到小排序,再运用动态规划思想递推求解。 #include<iostream>//数字游戏 using namespace std; struct XX {int a,b; }a[201]; int n,m,f[2][201],i,j; int comp(const void *a,const void *b) { return(*(XX*)b).b-(*(XX*)a).b; } int main()
贪心算法的应用实例
例 2.排队问题 【题目描述】 在一个医院 B 超室,有 n 个人要做不同身体部位的 B 超,已知每个人需要处理的时间 为 ti, (0<i<=n),请求出一种排列次序,使每个人排队等候时间总和最小。 输入数据:第 1 行一个正整数 n(你<=10000》 ,第 2 行有 n 个不超过 1000 的正整数 ti. 输出要求:n 个人排队时间最小总和。 输入输出样例 输入:4 5 10 8 7 输出: 67 【算法分析】 本题贪心算法:n 个人时间从小到大排序,就是这 n 个人最佳排队方案。求部分和的和 即为所求。 反证法证明:假设有最优解序列:s1,s2…sn,如 s1 不是最小的 Tmin,不妨设 sk=Tmin, 将 s1 与 sk 对调,显然,对 sk 之后的人无影响,对 sk 之前的人等待都减少了,(s1-sk)>0, 从而新的序列比原最优序列好,这与假设矛盾,故 s1 为最小时间,同理可证 s2…sn 依次最 小。
例 3.:数列极差问题 【题目描述】 在黑板上写了 N 个正整数做成的一个数列,进行如下操作:每一次擦去其中的两个数 a 和 b,然后在数列中加入一个数 a×b+1,如此下去直至黑板上剩下一个数,在所有按这种操 作方式最后得到的数中,最大的 max,最小的为 min,则该数列的极差定义为 M=max-min。 编程任务:对于给定的数列,编程计算出极差 M。 输入输出样例: 输入: 4 2 1 4 3 输出: 13 【算法分析】 当看到此题时,我们会发现求 max 与求 min 是两个相似的过程。若我们把求解 max 与 min 的过程分开,着重探讨求 max 的问题。 下面我们以求 max 为例来讨论此题用贪心策略求解的合理性。 讨论:假设经(N-3)次变换后得到3个数:a ,b , max' (max'≥a≥b) ,其中 max'是(N-2)个数经(N-3)次f变换后所得的最大值,此时有两种求值方式,设 其所求值分别为 z1,z2,则有:z1=(a×b+1)×max'+1,z2=(a×max'+1) ×b+1所以 z1-z2=max'-b≥0若经(N-2)次变换后所得的3个数为:m,a,
2
} int work(){ qsort(a+1,n,sizeof(a[0]),cmp);//按区间右端点由小到大排序 int i,j,k; int a1,a2; a1=a[1].right-1;a2=a[1].right;result=2; for(i=2;i<=n;i++) { if(a[i].left<=a1&& a[i].right>=a2)continue;//完全包含 if (a[i].left>a2 )//完全不包含 {a1=a[i].right-1;a2=a[i].right;result=result+2;} if (a[i].left>a1 && a[i].right>a2 && a[i].left<=a2) {a1=a2;a2=a[i].right;result++;}//只包含一个 } return result; } int main(){ freopen("range6.in","r",stdin); freopen("range6.out","w",stdout); cin>>n; int i; for(i=1;i<=n;i++) cin>>a[i].left>>a[i].right; cout<<work()<<endl; return 0; } 例 5.骆驼商队 Camel Trading 【题目描述】 在一片古老的大地上, 虽然商业已经非常繁荣, 但是那里的人们仍然延续着古老的交易 方式。他们牵着骆驼在城市之间往来奔波,贩运成批的商品,换来一袋袋的金币。 这片大陆上有 N 个城市,编号为 1……N。在一些城市之间有路可通,有路就有商队。 但是在不同的城市之间经商所得的收益不同, 在下面的这个 N=4 的例子中, 在城市 1 和城市 2 之间进行一次交易可以获得 40 枚金币,在城市 2 和 3 之间交易一次可以获得 50 枚金币, 等等。 1 40 2 30 50 30 3 20 4
1
b(m≥a≥b)且m不为(N-2)次变换后的最大值,即m<max'则此时所求得的最 大值为: z3=(a×b+1)×m+1此时 z1-z3=(1+ab) (max'-m)>0 所以此时不 为最优解。 所以若使第k(1≤k≤N-1)次变换后所得值最大,必使(k-1)次变换后所得 值最大(符合贪心策略的特点 2) ,在进行第k次变换时,只需取在进行(k-1)次变换 后所得数列中的两最小数p,q施加f操作:p←p×q+1,q←∞即可(符合贪心策略特 点 1) ,因此此题可用贪心策略求解。在求min 时,我们只需在每次变换的数列中找到两个 最大数p,q施加作用 f:p←p×q+1,q←-∞即可.原理同上。 这是一道两次运用贪心策略解决的一道问题,它要求选手有较高的数学推理能力。 例 4.整数区间 range.cpp 【题目描述】 我们定义一个整数区间[a,b],a,b 是一个从 a 开始至 b 结束的连续整数的集合。 编一个 程序,对给定的 n 个区间,找出满足下述条件的所含元素个数最少的集合中元素的个数: 对 于 所 给 定 的 每 一 个 区 间 , 都 至 少 有 两 个 不 同 的 整 数 属 于 该 集 合 。 (1<=n<=10000, 0<=a<=b<=1000) 输入输出格式: 输入:第一行一个正整数 n,接下来有 n 行,每行给定一个区间的 a,b 值 输出:一个正整数,即满足条件的集合所包含的最少元素个数 输入输出样例 输入: 输出: 4 4 3 6 2 4 0 2 4 7 【算法分析】 本题数据规模较大,用搜索做会超时,而动态规划无从下手。考虑贪心算法。题目意思 是要找一个集合,该集合中的数的个数既要少又要和所给定的所有区间有交集。 (每个区间 至少有两个该集合中的数) 。我们可以从所给的区间中选数,为了选尽量少的数,应该使所 选的数和更多的区间有交集这就是贪心的标准。一开始将所有区间按照右端点从小到大排 序。从第一个区间开始逐个向后检查,看所选出的数与所查看的区间有无交集,有两个则跳 过,只有一个数相交,就从当前区间中选出最大的一个数(即右端点) ,若无交集,则从当 前区间选出两个数,就(右端点,右端点-1) ,直至最后一个区间。 #include <iostream>//整数区间问题 using namespace std; struct prince{ int left,right;//区间左右端点 }a[10000]; int n; int result;//存放结果中的数 int cmp(const void *a,const void *b){ return (*(prince *)a).right-(*(prince *)b).right;
4wenku.baidu.com
一个 v1;然后将 v1 上的另一条边 e2 分配给 e2 的另一个端点 v2;将 v2 上的另一条边 e3 分配给 e3 的另一个端点 v3; ……如此重复直到将 en 分配给 vn, 即图中所有的边都已分配, 结束算法。 6、将图中权最小的边不分配而直接删去。如果此时图仍然连通,则转 2;否则对这个图的 两个连通分量分别执行本算法。