ACM集训day3

7.13

要点:贪心算法

note:分成子问题,分别求最优解
找规律->得猜想->证猜想->写代码
例题:hdu2037、hdu2021、nyoj891

常用技巧: 0.sort函数的使用
1.sort自定义排序规则sort(,,cmp)
2.结构体排序

思考题:

nyoj1170

描述
小明和小红在打赌说自己数学学的好,于是小花就给他们出题了,考考他们谁NB,题目是这样的给你N个数
在这n个数之间添加N-1个*或+,使结果最大,但不可以打乱原顺序,请得出这个结果

1 3 5
结果是(1+3)*5=20;最大
可以添加若干个括号,但一定要保证配对,但是每两个数之间只可能有一个*或+
数列最前和最后不应有+或乘
小明想赢小红但是他比较笨,请你帮帮他
输入
多组测试数据以EOF结束,每组有一个n(n<10000),然后有n个正整数a[i](1<=a[i]<=20)
输出
输出最大的结果由于结果比较大,结果对10086取余

练习

A题 发工资咯:)

note:好久没做过这种输入0就结束程序的了,还以为每个样例以0结束my god…MARK一下

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int a[10005];

bool cmp(int a,int b)  //sort大到小排
{
    return a>b;
}
int main()
{
    int n;
    int c[6]={100,50,10,5,2,1};
    while(scanf("%d",&n)!=EOF&&n)  //0结束
    {
        memset(a,0,sizeof(a));
        int i,j;
        int count=0;
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
            if(!a[i])
                break;
    }
    sort(a,a+n,cmp);    //可以不要排序,没多大意义
    for(i=0;i<n;i++)
        for(j=0;j<6;j++)
        {
            if(c[j]>a[i])
                continue;
            else if(c[j]==a[i])
            {
                count++;
                break;
            }

            else
            {
                int t;
                t=a[i]/c[j];
                count+=t;
                a[i]=a[i]%c[j];
            }

        }
    printf("%d\n",count);
    }
    return 0;
}

============================我是分割线===============================

C题 Crossing River

**
note:多找找规律

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

int main()
{
    int i,n,t;
    scanf("%d",&t);
    while(t--)
    {
        int time=0,a[1000];
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d",&a[i]);
        }
        sort(a,a+n);
        //time=a[0]+a[1]+a[n-1];

            while(n>=4)
                {
                    int t1,t2;
                    t1=a[0]+a[1]*2+a[n-1];  //两个最慢的走
                    t2=a[n-1]+a[n-2]+a[0]*2; //最快的来回带慢的飞~
                    time+=min(t1,t2);     //比较取时间少的方案
                    n-=2;
                }
                 if(n==3)
                    time+=a[0]+a[1]+a[2];
                else if(n==2)
                    time+=a[1];
                else if(n==1)
                    time+=a[0];        
            printf("%d\n",time);
    }
    return 0;
}

D题 今年暑假不AC

note:结构体排序,真的很好用!按结束时间升序

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

struct temp
{
    int a,b;
};
typedef struct temp T;

bool cmp(T m,T n)
{

    return m.b<n.b;
}
int main()
{
    int n,i,j;
    while(scanf("%d",&n)!=EOF&&n)
    {
        T f[1000];
        int count=1;
        for(i=0;i<n;i++)
        {
            scanf("%d %d",&f[i].a,&f[i].b);
        }
        sort(f,f+n,cmp);
        for(i=1,j=0;i<n;i++)
            if(f[i].a>=f[j].b)
            {
                j=i;
                count++;
            }

        printf("%d\n",count);
    }
    return 0;
}

============================我是分割线===============================

E题 Hero

**
note:这题跟基友讨论了很久,终于理解透彻了!

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;

struct temp
{
    double dp,hp; /*这里用double,是为了下面(*)式子中的除法能比较出高下,否则31/3和20/2是一样的*/
};
typedef struct temp T;

bool cmp(T m,T n)
{
    /*double d1,d2;           //如果上面用int,这里就不能去掉,下面改成return d1>d2;
    d1=1.0*m.dp/m.hp;
    d2=1.0*n.dp/n.hp;*/ //(*)

        return (m.dp/m.hp)>(n.dp/n.hp); //(**)
        /*原来WA是因为上面(*)虽然注释掉,但是作用没发挥出来,结构体那里又用了int,导致排序出问题
 dps/hp来计算敌人的威胁程度是因为我联想到初高中的时候,我参加铅球比赛,我几乎是成绩是排3,然而我的体重几乎是全场最轻,就是说用 距离/体重 来算成绩的话,我肯定就是第一了...*/
}
int main()
{

    int n,i;
    while(scanf("%d",&n)!=EOF)
    {
        T f[1000];
        int attack=0;
        int loss=0;
        for(i=0;i<n;i++)
        {
            scanf("%lf %lf",&f[i].hp,&f[i].dp);
            attack+=f[i].dp;
        }
        sort(f,f+n,cmp);

        for(i=0;i<n;i++)
        {
            loss+=attack*f[i].hp;
            attack-=f[i].dp;
        }
        printf("%d\n",loss);
    }
    return 0;
}

============================我是分割线===============================

F题 Subsequence

**
note:用到记忆化的思想,节省时间

#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int a[100005];
int sum[100005];
int main()
{
    int n,s,i,j,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d %d",&n,&s);
        memset(a,0,sizeof(a));
        memset(sum,0,sizeof(sum));

        int ans=n+1;
        for(i=0;i<n;i++)       
            scanf("%d",&a[i]);

        for(i=1;i<=n;i++)
        {
            sum[i]=sum[i-1]+a[i-1];  //名副其实的前i项,就是sum[0]==0;
        }
        int j=1;
        int tag=1;
        if(a[0]>=s) ans=1;
        else if(sum[n]<s);  //打分号,不作处理~一开始就看总和是否大于s
            //ans=n+1;
        else{
            for(i=1;i<=n;i++) /*虽然这里是二层循环,但是时间复杂度只是第一层的线性关系,并不是                                           指数关系,因为第二层循环的j实际上是跟第一层的i是并驱的,sum[j]-sum[i-1]一旦大于s,j就停下来等i*/

            {
                for(;sum[j]-sum[i-1]<s;)
                {
                    if(j==n)
                        tag=0;
                    j++;
                }
                if(j<=n&&sum[j]-sum[i-1]>=s)
                    ans=min(ans,j-i+1);   //取范围最小值
                if(!tag)
                    break;
            }
        }
        if(ans<=n)
            printf("%d\n",ans);
        else
            printf("0\n");
    }
    return 0;
}

对F题的循环用表格举例子描述一下:如输入n=10,s=15 5 6 7 10

ij第i个数到第j个数的和大于s时区间长度
115<(s=15)(不能直接打5小于s,好奇怪…)
12(j往右跑)11<(s=15)
13(j往右跑)18>=(s=15)3
2(i往右跑)313<(s=15)
24(j往右跑)23>=(s=15)3
3(i往右跑)417>=(s=15)2

*由此可见时间复杂度只是n的线性关系O(n)

贪心算法感觉学得不是很好,我是不是不怎么贪心啊(逃
过题排前几的都是贪心鬼!(捂脸

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值