贪心算法

合并石子--Garsia-Wachs贪心

百般思念 提交于 2019-12-02 20:53:03
题意: 有n堆石子,每次可以合并相邻两个石子,代价为两堆石子的和,求将这堆石子合并为一堆的最小代价。 这道题可以用平衡树做,只是维护的东西很多很多,会非常难受 所以我就退而求其次,选择了ZJC大爷的卡常做法 1e5的数据范围也能在1s内轻松卡过啦!!! 思路与 Garsia-Wachs算法一致 代码如下 #include<bits/stdc++.h> using namespace std; unsigned int tot; unsigned long long a[500005]; int n; int read() { char c; int x; for(c=getchar();c!='-'&&(c>'9'||c<'0');c=getchar()); if(c=='-') { x=0; for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return -x; } else { x=c-'0'; for(c=getchar();c>='0'&&c<='9';c=getchar()) x=x*10+c-'0'; return x; } } unsigned long long ans; void unionn(const unsigned int x) { unsigned int i,j,d; unsigned

[算法总结]贪心

半腔热情 提交于 2019-12-02 17:12:41
目录 例题: 1. P2887 [USACO07NOV]防晒霜Sunscreen 2. P2859 [USACO06FEB]摊位预订Stall Reservations 3. P1080 国王游戏 4. P1417 烹调方案 贪心算法是每次选举决策时保证当前状况最优(局部最优)策略的算法。因此在使用贪心时需要保证整体最优解可以由局部最优解导出。 贪心算法的使用通常需要证明,以下为几种常见的证明方法: 1. 邻项交换: 在任意局面下,任何元素位置的改变都会影响当前局面的改变。该方法NOIP曾有涉及。 对局面元素的排序可以为贪心策略提供证明。 2. 范围缩放: 扩大局部最优解的范围不会影响整体最优的情况。 3. 反证法,归纳法: 如同字面意思。 (=´ω`=) 例题: 1. P2887 [USACO07NOV]防晒霜Sunscreen 分析: 把每个奶牛按照minSPF递减排序,并在防晒霜中找SPF最大的给这头奶牛用(在合理范围内)。假如有两瓶防晒霜x,y可用,其中spf[x]>spf[y]。那么对于下一头奶牛来说,有x,y都能用,只能用y,和x,y都不能用这三种情况。显然,我们将spf低的防晒霜给后面的奶牛用会更优。 代码如下: #include<bits/stdc++.h> #define N 5000 using namespace std; struct node{ int l

python常用算法(6)——贪心算法,欧几里得算法

夙愿已清 提交于 2019-12-02 15:13:01
1,贪心算法   贪心算法(又称贪婪算法)是指,在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的的时在某种意义上的局部最优解。   贪心算法并不保证会得到最优解,但是在某些问题上贪心算法的解就是最优解。要会判断一个问题能否用贪心算法来计算。贪心算法和其他算法比较有明显的区别,动态规划每次都是综合所有问题的子问题的解得到当前的最优解(全局最优解),而不是贪心地选择;回溯法是尝试选择一条路,如果选择错了的话可以“反悔”,也就是回过头来重新选择其他的试试。 1.1 找零问题   假设商店老板需要找零 n 元钱,钱币的面额有100元,50元,20元,5元,1元,如何找零使得所需钱币的数量最少?(注意:没有10元的面额)   那要是找376元零钱呢? 100*3+50*1+20*1+5*1+1*1=375   代码如下: # t表示商店有的零钱的面额 t = [100, 50, 20, 5, 1] # n 表示n元钱 def change(t, n): m = [0 for _ in range(len(t))] for i, money in enumerate(t): m[i] = n // money # 除法向下取整 n = n % money # 除法取余 return m, n print(change(t, 376)) # ([3,

c++用贪心算法解决汽车加油问题

≡放荡痞女 提交于 2019-12-02 15:00:39
汽车加油问题 Time Limit: 1000 ms Memory Limit: 65536 KiB 一辆汽车加满油后可行驶n公里。旅途中有若干个加油站。设计一个有效算法,指出应在哪些加油站停靠加油,使沿途加油次数最少。并证明算法能产生一个最优解。 对于给定的n和k个加油站位置,计算最少加油次数。 Input 输入数据的第一行有2 个正整数n和k(n≤5000,k≤1000),表示汽车加满油后可行驶n公里,且旅途中有k个加油站。接下来的1 行中,有k+1 个整数,表示第k个加油站与第k-1 个加油站之间的距离。第0 个加油站表示出发地,汽车已加满油。第k+1 个加油站表示目的地。 Output 将计算出的最少加油次数输出。如果无法到达目的地,则输出“No Solution!”。 Sample Input 7 7 1 2 3 4 5 1 6 6 Sample Output 4 #include <iostream> using namespace std; int main() { int n; int k; int a[1001]={0}; cin>>n>>k; for(int i=1;i<=k+1;i++) cin>>a[i]; int s=0; //判断接下来路程相加是否大于n int c=0; //加油次数 int t=0; //标记走过的路程 for(int i=0;i<

基于贪心算法对整数区间问题(CEOI1997)的深入研究

一曲冷凌霜 提交于 2019-12-02 15:00:34
题目 题目描述 请编程完成以下任务: 1.从文件中读取闭区间的个数及它们的描述; 2.找到一个含元素个数最少的集合,使得对于每一个区间,都至少有一个整数属于该集合,输出该集合的元素个数。 输入 首行包括区间的数目n,1≤n≤10000,接下来的n行,每行包括两个整数a,b,被一空格隔开,0≤a≤b≤10000,它们是某一个区间的开始值和结束值。 输出 第一行集合元素的个数,对于每一个区间都至少有一个整数属于该区间,且集合所包含元素数目最少。 样例输入 4 3 6 2 4 0 2 4 7 样例输出 2 算法分析 这是CEOI(中欧信息学竞赛)1997的一道题,仔细想想应该不难知道应该用贪心去做。 我就看门见山地讲吧! 先将每个区间的右端点排一下序(从小到大),从小到大地对每个区间进行处理,对于每一个区间,它的右端点在数轴上肯定在上一个区间的右侧(因为我们是从小到大排的序的呀!),那要让我们答案集合中的元素尽量少,那就选它上一个区间的右端点作为答案集合的一个元素(这就是这道题的贪心之处),于是就会有两种情况。 当前我们处理的区间的左端点比它的上一个区间的右端点要大。(如下图) 此时我们无法让一个整数属于这两个集合,于是我们就得增加一个整数 另外一种情况就是当前我们处理的区间的左端点小于等于它上一个区间的右端点 此时我们就可以让图中红色的点属于这两个集合,也就不用增加整数了

歌手与小朋友照相 【贪心】

可紊 提交于 2019-12-02 15:00:26
Scanner sc = new Scanner ( System . in ) ; int n = sc . nextInt ( ) ; int s = sc . nextInt ( ) ; int index = 0 ; int num = 0 ; int [ ] [ ] x = new int [ n ] [ 2 ] ; for ( int i = 0 ; i < n ; i ++ ) { for ( int j = 0 ; j < 2 ; j ++ ) { x [ i ] [ j ] = sc . nextInt ( ) ; } } for ( int i = 0 ; i < n ; i ++ ) { if ( s < x [ i ] [ 1 ] ) { //如果这一位不满足 if ( i != n - 1 ) { // 如果不是最后一位 if ( s >= x [ i + 1 ] [ 1 ] ) { //判断是否大于所需要的积木数 s = ( s - x [ i + 1 ] [ 1 ] ) + x [ i + 1 ] [ 0 ] + x [ i + 1 ] [ 1 ] ; // 给小朋友,然后拿到所有积木 index ++ ; // 拍照+1 } } } } int len = n - index ; // 减去已经拍过照的 for ( int i = 0 ; i <

c++用贪心算法解决活动选择问题

拜拜、爱过 提交于 2019-12-02 14:56:48
活动选择 Time Limit: 1000 ms Memory Limit: 65536 KiB 学校的大学生艺术中心周日将面向全校各个学院的学生社团开放,但活动中心同时只能供一个社团活动使用,并且每一个社团活动开始后都不能中断。现在各个社团都提交了他们使用该中心的活动计划(即活动的开始时刻和截止时刻)。请设计一个算法来找到一个最佳的分配序列,以能够在大学生艺术中心安排不冲突的尽可能多的社团活动。 比如有5个活动,开始与截止时刻分别为: 最佳安排序列为:1,4,5。 Input 第一行输入活动数目n(0<n<100); 以后输入n行,分别输入序号为1到n的活动使用中心的开始时刻a与截止时刻b(a,b为整数且0<=a,b<24,a,b输入以空格分隔)。 Output 输出最佳安排序列所包含的各个活动(按照活动被安排的次序,两个活动之间用逗号分隔)。 Sample Input 6 8 10 9 16 11 16 14 15 10 14 7 11 Sample Output 1,5,4 #include <iostream> using namespace std; int main() { int n; int a[101]; //开始时间 int b[101]; //结束时间 int c[101]; //活动序号 cin>>n; int da; int db; int dc; for

贪心算法(2)

萝らか妹 提交于 2019-12-02 14:27:32
5.11 ZOJ1029-Moving Tables 这层楼沿着走廊南北向的两边各有200个房间。最近,公司要做一次装修,需要在各个办公室之间搬运办公桌。 由于走廊狭窄,办公桌都很大,走廊里一次只能通过一张办公桌。必须制定计划提高搬运效率。 经理制定如下计划:一张办公桌从一个房间移到另一个房间最多用十分钟。当从房间i移动一张办公桌到房间j,两个办公室之间的走廊都会被占用。所以,每10分钟内,只要不是同一段走廊,都可以在房间之间移动办公桌。 输入 输入数据有T组测试例,在第一行给出测试例个数T。 每个测试例的第一行是一个整数N(1≤N≤200),表示要搬运办公桌的次数。接下来N行,每行两个正整数s和t,表示一张桌子,是从房间号码s移到到房间号码t。 输出 每组输入都有一行输出数据,为一整数T,表示完成任务所花费的最小时间。 在经理给出的说明表格中,已经明确地描述了算法: (从房间30到50)和(从房间60到90)是允许的,因为没有占用公共的走廊; (从房间20到40)和(从房间31到80)是不允许的,因为要占用公共的走廊。 我们将每个房间之间的走廊作为一个统计单位,当所有的办公桌都搬运完成之后,看看这段走廊到底需要占用多少次?然后统计所有的走廊被占用的最大值max,这个值就是要单独安排的搬运次数,乘以10就是总的搬运时间。 int i, j; int move[200]; int N

会场安排问题(贪心)

雨燕双飞 提交于 2019-12-02 02:02:41
题目链接: http://acm.sdibt.edu.cn/JudgeOnline/problem.php?id=4809 思路: 能放在一个会场里的活动的前提是,当前活动的开始时间大于等于上一个活动的结束时间。 首先把一个活动的开始时间和结束时间放在两个数组中再进行排序,这样得到的就是最小开始时间和最小结束时间,k初值为0,只要当前的开始时间小于结束时间,k++,由于结束时间是降序的,如果不小于这个结束时间,就后移一位,这样就得到了会场的次数。贪心算法的思想就是只考虑当前的情况。而不顾虑全局最优,所以我们只要能保证下一个活动的开始时间能小于这个活动的结束时间就行。 #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n; cin >> n; int a[10005],b[10005]; for(int i = 0; i < n; i++) { cin >> a[i] >> b[i]; } sort(a,a+n); sort(b,b+n); int k = 0,j = 0; for(int i = 0; i < n; i++) { if(a[i] < b[j]) k++; else j++; } cout << k << endl;

货币兑换问题(贪心法)——Python实现

半腔热情 提交于 2019-12-01 17:39:44
# 贪心算法求解货币兑换问题 # 货币系统有 n 种硬币,面值为 v1,v2,v3...vn,其中 v1=1,使用总值money与之兑换,求如何使硬币的数目最少,即 x1,x2,x3...xn 之和最小 # 输入:各种货币的面值 v1,v2,v3...vn;要兑换的总值 money # 输出:兑换得到最少的货币数量 1 # 修改面额 2 v = [50,10,5,2,1] 3 # 修改要兑换的货币量money 4 money = 253 5 # 每种货币初始数量为 0 6 x = [0]*len(v) 7 # 总货币初始数量为 0 8 count = 0 1 # 从最大面额开始兑换,剩余不足兑换大面额,则接着兑换小面额,直到兑换完成 2 for i in range (0,len(v)): 3 x[i] = money // v[i] # 取整符号// 4 money = money % v[i] # 取余符号% 5 for i in range (0,len(v)): 6 count = x[i] + count 1 print('通过贪心算法兑换得到的货币数量:',count) 2 print(' 其中,面值为 ',v) 3 print(' 的货币数量分别是 ',x) 运行结果: 1 要兑换的货币数量为: 253 2 通过贪心算法兑换得到的货币数量: 7 3 其中,面值为