ACM集训day3

来源:互联网 发布:知乎关注最多的人 编辑:程序博客网 时间:2024/05/01 20:33

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

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

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

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

0 0
原创粉丝点击