One Day One Step 之贪心算法(1)



终于来到了贪心算法了!寒假的时候家里没网络,只能看书或者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次,WA9次!最开始我的想法很简单,就是尽量使雷达往右靠,不过我一开始的想法是错的,就是先将点的坐标按照X从小到大进行排序,通过最后一个点来确定第一个雷达的,然后进行历遍,如果发现有一个岛屿的到雷达的距离大于雷达的检测半径,就以这个点在确定一个新的雷达的坐标。问题是,用这种做法无法保证后面的岛屿的坐标都在新建的雷达的范围内!所以,这种想法是错误的!


正确的解法是:先将点的坐标按照X的递增进行排序!然后以每一个点为圆形,雷达的检测半径为半径,画圆。这样圆与x轴的交点情况就是该岛屿的能否被检测到还有被监测的范围!


第一种情况:岛屿的纵坐标大于检测半径,肯定无法检测得到,输出-1


第二种情况:岛屿的纵坐标小于或等于检测半径,这能够被检测到!保存当前的右交点的x坐标!在这种情况下,我们就可以看下一个点能否跟他一起被同一个雷达检测到了:


首先说明一点,那就是所画的圆与x轴的右交点是该点能够被检测到的极大点,如果超过的话肯定检测不到!


首先,如果下一个岛屿的左交点的x坐标大于上一个岛屿的右交点的x坐标,这不能被同一个雷达同时检测到,雷达数自增一次!并保存当前岛屿的右交点的x坐标供下一次的比较!


如果如果下一个岛屿的左交点的x坐标小于上一个岛屿的右交点的x坐标,这里又有两种情况!


  1. 下一个岛屿的右交点的x坐标大于上一个岛屿的右交点的x坐标,那么,直接看下一个岛屿的情况!因为这种情况只能说明当前雷达的位置两者都能够检测到!

  2. 下一个岛屿的右交点的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 !

猜你喜欢

转载自blog.csdn.net/u011564456/article/details/19697077
one
今日推荐