贪心算法(一)

3 篇文章 0 订阅
1 篇文章 0 订阅

1、poj1700过河问题

先排序,然后假设数据为t1 t2 t3 t4 t5 t6 t7 t8,只会有两种方式:
方式一:最快的两个作为划回的船,两个来回运走两个最慢的,好处是最慢的和次慢的组合消除掉次慢的时间,坏处是往回划的有一半是次快的。时间:t1+2*t2+t8
方式二:只有最快的作为划回的船,两个来回运走两个最慢的,好处是往回划的时间是最优的,坏处是往对岸划的次慢的时间也走了。时间:2*t1+t7+t8
综合两种情况,只需要把数据划分为1,2,3,大于4个这四种情况,大于4的时候比较方式一和二取最小值,1、2、3的时候单独讨论即可

#include <stdio.h>
#include <stdlib.h>

void sort(int *pe,int n)
{
    int i,j;
    int temp;
    for(i=0;i<n;i++)
    {
        for(j=n-1;j>i;j--)
        {
            if(pe[j]<pe[j-1])
            {
                temp=pe[j];
                pe[j]=pe[j-1];
                pe[j-1]=temp;
            }
        }
    }
}

int main()
{
    int t,n;
    int pe[1000];
    int i;
    int sum;
    scanf("%d",&t);
    while(t--)
    {
        sum=0;
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d",&pe[i]);
        }
        sort(pe,n);
        while(n>0)
        {
            if(n==1)
            {
                sum+=pe[0];
                n=0;
            }else if(n==2)
            {
                sum+=pe[1];
                n=0;
            }else if(n==3)
            {
                sum+=(pe[1]+pe[0]+pe[2]);
                n=0;
            }else
            {
                int a1=pe[0]+pe[1]*2+pe[n-1];
                int a2=pe[0]*2+pe[n-1]+pe[n-2];
                sum+=a1<a2?a1:a2;
                n-=2;
            }
        }
        printf("%d\n",sum);
    }
    return 0;
}

2、poj1328海岸线问题

这是一道区间覆盖类问题
第一步:输入时,求以海岛为圆心画圆与x轴的交点,两个交点之间放置雷达则可覆盖该海岛,保存这些线段到数组。
第二步:按线段左起点递增排序
第三步:从后向前比较,若i和i-1有交集则更新为交集,若无交集则增加雷达

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

void sort(double a[1000][2],int n)
{
    int i,j;
    double temp;
    for(i=0;i<n;i++)
    {
        for(j=n-1;j>i;j--)
        {
            if(a[j][0]<a[j-1][0])
            {
                temp=a[j][0];
                a[j][0]=a[j-1][0];
                a[j-1][0]=temp;
                temp=a[j][1];
                a[j][1]=a[j-1][1];
                a[j-1][1]=temp;
            }
        }
    }
}

int main()
{
    int n,d;
    int i;
    double co[1000][2];
    int x1,x2;
    int num,flag;
    int t=1;
    while(scanf("%d %d",&n,&d)!=EOF&&n&&d)
    {
        num=0;flag=0;
        for(i=0;i<n;i++)
        {
            scanf("%d %d",&x1,&x2);
            if(x2>d)
            {
                flag=1;
            }
            co[i][0]=x1-sqrt(pow(d,2)-pow(x2,2));
            co[i][1]=x1+sqrt(pow(d,2)-pow(x2,2));
        }
        if(flag)
        {
            printf("Case %d: -1\n",t++);
        }else
        {
            sort(co,n);
            for(i=n-1;i>0;i--)
            {
                if(co[i][1]<=co[i-1][1])
                {
                    co[i-1][0]=co[i][0];
                    co[i-1][1]=co[i][1];
                }else if(co[i][0]<=co[i-1][1])
                {
                    co[i-1][0]=co[i][0];
                }else
                {
                    num++;
                }
            }
            printf("Case %d: %d\n",t++,num+1);
        }
    }
    return 0;
}

3、poj2376

纯区间覆盖类问题,上一题是分散的区间数量,这一题就是单纯的区间覆盖了。按左端点从左到右覆盖,每次选取剩余线段最大的。
这里[1,2]到[3,4]这种也可以链接。

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int n,t;
    int a[25000][2];
    int i,j,temp[1][2];
    int flag,num;
    while(scanf("%d %d",&n,&t)!=EOF)
    {
        flag=1;
        num=0;
        for(i=0;i<n;i++)
        {
            scanf("%d %d",&a[i][0],&a[i][1]);
            temp[0][0]=a[i][0];temp[0][1]=a[i][1];
            for(j=i-1;j>=0&&(a[j][0]>temp[0][0]);j--)
            {
                a[j+1][0]=a[j][0];
                a[j+1][1]=a[j][1];
            }
            a[j+1][0]=temp[0][0];
            a[j+1][1]=temp[0][1];
        }
        if(a[0][0]>1)
        {
            flag=0;
        }else
        {
            temp[0][0]=1;temp[0][1]=0;
            int max=0;
            for(i=0;i<n;i++)
            {
                if(a[i][0]<=temp[0][1]+1)
                {
                    if(i==n-1)
                    {
                        if(temp[0][1]<a[i][1])
                        {
                            num++;
                            temp[0][1]=a[i][1];
                        }
                    }else
                    {
                        max=a[i][1]>max?a[i][1]:max;
                    }
                }else
                {
                    if(temp[0][1]<max)
                    {
                        num++;
                        temp[0][1]=max;
                    }
                    if(a[i][0]>temp[0][1]+1)
                    {
                        flag=0;
                        break;
                    }else if(i==n-1)
                    {
                        if(temp[0][1]<a[i][1])
                        {
                            num++;
                            temp[0][1]=a[i][1];
                        }
                    }else
                    {
                        max=a[i][1];
                    }
                }
                if(temp[0][1]==t) break;
            }
        }
        if(temp[0][1]!=t) flag=0;
        if(flag)
        {
            printf("%d\n",num);
        }else
        {
            printf("-1\n");
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值