终于来到了贪心算法了!寒假的时候家里没网络,只能看书或者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 !