One Day One Step 之贪心算法(1)
2014-02-22 20:04
633 查看
终于来到了贪心算法了!寒假的时候家里没网络,只能看书或者PDF,就发现贪心算法这个东西老是出现在我的视野中,草草地看了一遍之后发现这个东西没什么用,既没有固定的模式,而且由于书上讲的都太理论了,所以不知道怎么用这个东西!直到昨天比赛后,跟同学讨论后发现有几道题是应该用贪心算法的!这才开始重视起来!昨天到刚才做了几道有关于贪心的题目,算是有点理解。特写出来与大家分享!
第一道是HDU上的“今年暑假不AC”:题目很简单,我说一下我的思路!
题目的要求是求出能够看的最多的节目。所以,先不管节目时间的长短,如果我们看完一个节目后能够剩余更多的时间,就能够看更多的节目,而剩余的时间是有这一次所看节目的结束时间决定的!所以,我们可以通过排序,将节目按照结束时间进行排序。然后,如果,下一个节目的开始时间大于或者等于现在看的节目的结束时间,说明下一个节目与当前看的节目不冲突,或者说两者是相容的,那么可看的节目数就自增一次!
下面是代码:
第二道是福州OJ的“区间相交问题”:
题目是要求去掉尽可能少的闭区间,使剩下的闭区间都不相交。思路很简单,就是求出最长的不相交的闭区间的个数,然后所有的区间数减去他就可以了!而求最长不相交的闭区间个数的解法跟上面那道题的思路是一样的。这道题唯一算得上是陷阱的就是所输入的数据不一定是左小右大的,所以如果不满足就必须交换过来!上代码!
最后这一道是POJ的“Radar Installation”,是我做得最久,提交次数最多的一道,总共交了10次,WA了9次!最开始我的想法很简单,就是尽量使雷达往右靠,不过我一开始的想法是错的,就是先将点的坐标按照X从小到大进行排序,通过最后一个点来确定第一个雷达的,然后进行历遍,如果发现有一个岛屿的到雷达的距离大于雷达的检测半径,就以这个点在确定一个新的雷达的坐标。问题是,用这种做法无法保证后面的岛屿的坐标都在新建的雷达的范围内!所以,这种想法是错误的!
正确的解法是:先将点的坐标按照X的递增进行排序!然后以每一个点为圆形,雷达的检测半径为半径,画圆。这样圆与x轴的交点情况就是该岛屿的能否被检测到还有被监测的范围!
第一种情况:岛屿的纵坐标大于检测半径,肯定无法检测得到,输出-1!
第二种情况:岛屿的纵坐标小于或等于检测半径,这能够被检测到!保存当前的右交点的x坐标!在这种情况下,我们就可以看下一个点能否跟他一起被同一个雷达检测到了:
首先说明一点,那就是所画的圆与x轴的右交点是该点能够被检测到的极大点,如果超过的话肯定检测不到!
首先,如果下一个岛屿的左交点的x坐标大于上一个岛屿的右交点的x坐标,这不能被同一个雷达同时检测到,雷达数自增一次!并保存当前岛屿的右交点的x坐标供下一次的比较!
如果如果下一个岛屿的左交点的x坐标小于上一个岛屿的右交点的x坐标,这里又有两种情况!
下一个岛屿的右交点的x坐标大于上一个岛屿的右交点的x坐标,那么,直接看下一个岛屿的情况!因为这种情况只能说明当前雷达的位置两者都能够检测到!
下一个岛屿的右交点的x坐标小于上一个岛屿的右交点的x坐标,那么,必须将下一个岛屿的右交点的x坐标保存下来作为下一次比较的标准!因为这一种情况说明下一个岛屿的雷达监测范围包含在上一个之中,如果还依照上一个上一个岛屿的右交点的x坐标作为比较标准,那么有可能超出下一个标准的范围!
说了这么多,接下来是代码实现:
贪心算法这一系列还没完,我还会继续做,继续写!实现我的One Day One Step !
终于来到了贪心算法了!寒假的时候家里没网络,只能看书或者PDF,就发现贪心算法这个东西老是出现在我的视野中,草草地看了一遍之后发现这个东西没什么用,既没有固定的模式,而且由于书上讲的都太理论了,所以不知道怎么用这个东西!直到昨天比赛后,跟同学讨论后发现有几道题是应该用贪心算法的!这才开始重视起来!昨天到刚才做了几道有关于贪心的题目,算是有点理解。特写出来与大家分享!
第一道是HDU上的“今年暑假不AC”:题目很简单,我说一下我的思路!
题目的要求是求出能够看的最多的节目。所以,先不管节目时间的长短,如果我们看完一个节目后能够剩余更多的时间,就能够看更多的节目,而剩余的时间是有这一次所看节目的结束时间决定的!所以,我们可以通过排序,将节目按照结束时间进行排序。然后,如果,下一个节目的开始时间大于或者等于现在看的节目的结束时间,说明下一个节目与当前看的节目不冲突,或者说两者是相容的,那么可看的节目数就自增一次!
下面是代码:
#include <stdio.h> #include <stdlib.h> #define N 101 typedef struct { int start; int end; }program; int comp( const void * a, const void * b ) { program * a_ = ( program * ) a; program * b_ = ( program * ) b; return a_->end - b_->end; } int main() { int pronum; while( scanf( "%d", &pronum ) && pronum != 0 ) { program p[ N ]; int i; int tmpend, ans = 1; for( i = 0; i < pronum; i++ ) { scanf( "%d%d", &p[i].start, &p[i].end ); } qsort( p, pronum, sizeof( p[0]), comp ); tmpend = p[0].end; for( i = 1; i < pronum; i++ ) { if( tmpend <= p[i].start ) { ans++; tmpend = p[i].end; } } printf( "%d\n", ans ); } return 0; }
第二道是福州OJ的“区间相交问题”:
题目是要求去掉尽可能少的闭区间,使剩下的闭区间都不相交。思路很简单,就是求出最长的不相交的闭区间的个数,然后所有的区间数减去他就可以了!而求最长不相交的闭区间个数的解法跟上面那道题的思路是一样的。这道题唯一算得上是陷阱的就是所输入的数据不一定是左小右大的,所以如果不满足就必须交换过来!上代码!
#include <stdio.h> #include <stdlib.h> #define N 40001 typedef struct { int left; int right; }interval; int comp( const void * a, const void * b ) { interval * a_ = ( interval * ) a; interval * b_ = ( interval * ) b; return a_->right - b_->right; } int main( void ) { int num; while( scanf( "%d", &num ) != EOF ) { int i, t; int tmpright; interval point[ N ]; int ans = 1; for( i = 0; i < num; i++ ) { scanf( "%d%d", &point[i].left, &point[i].right ); if( point[i].left > point[i].right ) { t = point[i].left; point[i].left = point[i].right ; point[i].right = t; } } qsort( point, num, sizeof( point[ 0 ]), comp ); tmpright = point[0].right; for( i = 1; i < num; i++ ) { if( tmpright < point[i].left ) { ans++; tmpright = point[i].right; } } printf( "%d\n", num - ans ); } return 0; }
最后这一道是POJ的“Radar Installation”,是我做得最久,提交次数最多的一道,总共交了10次,WA了9次!最开始我的想法很简单,就是尽量使雷达往右靠,不过我一开始的想法是错的,就是先将点的坐标按照X从小到大进行排序,通过最后一个点来确定第一个雷达的,然后进行历遍,如果发现有一个岛屿的到雷达的距离大于雷达的检测半径,就以这个点在确定一个新的雷达的坐标。问题是,用这种做法无法保证后面的岛屿的坐标都在新建的雷达的范围内!所以,这种想法是错误的!
正确的解法是:先将点的坐标按照X的递增进行排序!然后以每一个点为圆形,雷达的检测半径为半径,画圆。这样圆与x轴的交点情况就是该岛屿的能否被检测到还有被监测的范围!
第一种情况:岛屿的纵坐标大于检测半径,肯定无法检测得到,输出-1!
第二种情况:岛屿的纵坐标小于或等于检测半径,这能够被检测到!保存当前的右交点的x坐标!在这种情况下,我们就可以看下一个点能否跟他一起被同一个雷达检测到了:
首先说明一点,那就是所画的圆与x轴的右交点是该点能够被检测到的极大点,如果超过的话肯定检测不到!
首先,如果下一个岛屿的左交点的x坐标大于上一个岛屿的右交点的x坐标,这不能被同一个雷达同时检测到,雷达数自增一次!并保存当前岛屿的右交点的x坐标供下一次的比较!
如果如果下一个岛屿的左交点的x坐标小于上一个岛屿的右交点的x坐标,这里又有两种情况!
下一个岛屿的右交点的x坐标大于上一个岛屿的右交点的x坐标,那么,直接看下一个岛屿的情况!因为这种情况只能说明当前雷达的位置两者都能够检测到!
下一个岛屿的右交点的x坐标小于上一个岛屿的右交点的x坐标,那么,必须将下一个岛屿的右交点的x坐标保存下来作为下一次比较的标准!因为这一种情况说明下一个岛屿的雷达监测范围包含在上一个之中,如果还依照上一个上一个岛屿的右交点的x坐标作为比较标准,那么有可能超出下一个标准的范围!
说了这么多,接下来是代码实现:
#include <stdio.h> #include <stdlib.h> #include <math.h> #define N 1001 typedef struct { double x; double y; }position; int comp( const void * a, const void * b ) { position * a_ = ( position * ) a; position * b_ = ( position * ) b; if( a_->x != b_->x ) { return a_->x - b_->x; } else { return a_->y - b_->y; } } int main( void ) { position island[ N ]; int allisland; double r = 0; double righttmp, lefttmp; int j = 1; start: while( scanf( "%d%lf", &allisland, &r ) && allisland != 0 || r != 0 ) { int i; int allradar = 1; for( i = 0; i < allisland; i++ ) { scanf( "%lf%lf", &island[i].x, &island[i].y ); } qsort( island, allisland, sizeof( island[0] ), comp ); if( allisland == 1 ) { if( island[0].y <= r ) { printf( "Case %d: 1\n", j++ ); goto start; } else { printf( "Case %d: -1\n", j++ ); goto start; } } righttmp = island[0].x + sqrt( r * r - island[0].y * island[0].y ); for( i = 0; i < allisland; i++ ) { if( i == 0 && island[i].y <= r ) { continue; } if( island[i].y > r ) { printf( "Case %d: -1\n" , j++ ); goto start; } if( island[i].y == r ) { if( island[i].x > righttmp ) { allradar++; righttmp = island[i].x; continue; } else { lefttmp = island[i].x; righttmp = island[i].x; continue; } continue; } else { lefttmp = island[i].x - sqrt( r * r - island[i].y * island[i].y ); } if( lefttmp <= righttmp ) { if( island[i].x + sqrt( r * r - island[i].y * island[i].y ) < righttmp ) { righttmp = island[i].x + sqrt( r * r - island[i].y * island[i].y ); } } else { allradar++; righttmp = island[i].x + sqrt( r * r - island[i].y * island[i].y ); } } printf( "Case %d: %d\n", j++, allradar ); } return 0; }
贪心算法这一系列还没完,我还会继续做,继续写!实现我的One Day One Step !
相关文章推荐
- One Day One Step 之Palindromic Squares
- One Algorithm A Day --- INSERTION-SORT--算法入门
- One Day One Step之平面分割问题
- HDU acm step:Chapter one section three(简单贪心)
- One Day One Step 之Greedy Gift Givers
- One Day One Step 之Dual Palindromes
- One Day One Step 之全错位排序
- One Day One Step之图论(1)
- One Day One Step 之Milking Cows
- One Day One Step 之Codeforce(2014.03.06)
- 贪心算法知识(二)
- 贪心算法---最短路径问题
- 贪心算法(5)
- The step of installation of JDK and basic of JAVA(Day 01)
- acm之贪心算法题目2
- hdu 2037(贪心算法之区间调度问题)
- 蓝桥杯竞赛题——算法训练【最大最小公倍数】贪心
- 贪心生成最小生成树-克鲁斯卡尔(Kruskal)算法(归并排序)(并查集)
- Verilog HDL In One Day (Verilog HDL 学习的第一天)
- 小白进阶之贪心算法-赫夫曼编码