zoukankan      html  css  js  c++  java
  • 中山DAy2——普及

    今天挺不友好的,早上忘记定闹钟,晚了半小时起床,然后早上信心满满打算弄他个300分。结果……132.2分·。WTF???


    T1:disease

    题意:有n头奶牛,k种细菌(k<=15),给你每头奶牛携带的细菌种类,问:若让选出所有奶牛携带细菌少于d种,最多选几头奶牛?

    思路:上手就用了动归,可能是昨天打积木那题,自己信心爆棚。然后……神奇的22.2分出炉啦!  之后,我痛定思痛,发现动归真的是伪得快。

    正解:反正k小,把可能情况枚举一下,最多也没几种。不就是$C_k^d$种吗?然后比较打擂台就可以了。

    见代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,ans,d,k,inf=-0x3f3f3f,flag[16],use[16]; 
    bool a[1001][16];
    void dfs(int x)
    {
        for(int i=use[x-1]+1;i<=d;i++)
        {
            if(flag[i]==0)
            {
                flag[i]=1;
                use[x]=i;
                if(x==k)
                {
                    for(int j=1;j<=n;j++)
                    {
                           for(int i=1;i<=d;i++)
                        {
                            if(a[j][i]==true&&flag[i]==0)
                              {
                            ans--;
                            break;
                            }
                        }
                    }
                    if(ans>inf)
                    inf=ans;
                    ans=n;
                }
                else
                dfs(x+1);    
                flag[i]=0;
                use[x]=0;
            }
        }
    }
    int main()
    {
        scanf("%d%d%d",&n,&d,&k);
        ans=n;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[0][0]);
            for(int j=1;j<=a[0][0];j++)
            {
                scanf("%d",&a[0][1]);
                a[i][a[0][1]]=true;
            }
        }
        dfs(1);
        printf("%d",inf);
        return 0;
    }

    注意事项:

    要开一个数组,依次向后走,去记录,万万不能从1到k来回搞,不然就不是$C_d^k$而是C!了。

    好题哉!!!


    T2: jumpcow

    题意:有一个序列,你可以选择其中任意个数组成一个子序列,其中有个弹跳值,弹跳值为子序列奇数项的和乘上偶数项的和,问:弹跳值最大为多少?

    思路:熟悉的操作,熟悉的味道——动归!一开始在考场上,把奇偶混在一起,没有分开奇数项和偶数项,只有10分。

    正解:奇偶分开是什么意思呢?很简单。就是设一个二维数组:a[n][2],其中第二维为1表示此项做奇数项是的情况,第二维为0表示此项是偶数项的情况。

    转移方程:a[n][1]=max(a[n-1][0]+a[n][1],a[n-1][1])这个意思就是:如果不选此项就是前一个奇数项,然后依次向后转移。若选此项就是前一项为偶数项那就加上。

                    同理:a[n][0]=max(a[n-1][1]-a[n][0],a[n-1][0])。

    神奇的O(n)算法!

    见代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,max1=-0x3f3f3f,max2=-0x3f3f3f,inf=-0x3f3f3f;
    int a[150001][2];
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i][1]);    
        }
        for(int i=2;i<=n;i++)
        {
            max1=-0x3f3f3f;
            max2=-0x3f3f3f;
            for(int j=1;j<i;j++)
            {
                if(a[j][1]>max1)
                max1=a[j][1];
                if(a[j][0]>max2)
                max2=a[j][0];
            }
            a[i][0]=max1-a[i][1];
            a[i][1]+=max2;    
        }
        for(int i=1;i<=n;i++)
        {
            if(inf<a[i][0])
            inf=a[i][0];
            if(inf<a[i][1])
            inf=a[i][1];
        }
        printf("%d",inf);
        return 0;
    }

    好题哉!!!


    T3:town

    题意:有一个被水淹没小镇,给你小镇每块地的高度,每块地上的水可以流到上、下、左、右当中不高于它高度的格子里,可以在任何格子里安装一台水泵,水泵可以抽走无限量的水。问:最少需要安装几台水泵可以抽走所有的水?

    正解:宽搜。先找到最低的格子,然后向高处拓展标记,如果没有抽完就找第二小的格子继续搜,以此类推。用一个变量记录一下次数即可。

    见代码:

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    using namespace std;
    int n,m,k,head,ans,tail=1;
    int h1[2501],l1[2501],p[5]={0,-1,1,0,0},y[5]={0,0,0,-1,1};
    char a[51][51];
    bool flag[51][51];
    void bfs(int h,int l)
    { 
        head=0;
        tail=1;
        h1[1]=h;
        l1[1]=l;
        flag[h][l]=true;
        while(head!=tail)
        {
            head++;
            for(int i=1;i<=4;i++)
            {
                if(a[h1[head]+p[i]][l1[head]+y[i]]>0&&flag[h1[head]+p[i]][l1[head]+y[i]]==false&&a[h1[head]+p[i]][l1[head]+y[i]]>=a[h1[head]][l1[head]])
                {
                    tail++;
                    h1[tail]=h1[head]+p[i];
                    l1[tail]=l1[head]+y[i];
                    flag[h1[tail]][l1[tail]]=true;
                }
            }
        }
    }
    int main()
    {
        scanf("%d",&k);
        for(int q=1;q<=k;q++)
        {
            ans=0;
            memset(a,-1,sizeof(a));
            memset(flag,false,sizeof(flag));
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;i++)
            {
                for(int j=1;j<=m;j++)
                cin>>a[i][j];
            }
            while(1)
            {
                bool flag2=false;
                int min=0x3f3f3f,minh=0,minl=0;
                for(int i=1;i<=n;i++)
                    for(int j=1;j<=m;j++)
                    {
                        if(a[i][j]<min&&flag[i][j]==false)
                        {
                            min=a[i][j];
                            minh=i;
                            minl=j;
                            flag2=true;
                        }
                    }
                if(flag2==false)
                break;
                bfs(minh,minl);
                ans++;    
            }
            printf("%d
    ",ans);
        }
        return 0;
    }

    好题哉!!!


    T4:cowtract

    最大生成树模板题:没啥好讲的,博主也不会讲,上网搜呗。

    见代码:

    #include<cstdio>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    int n,m,ans,ans1,fa[20001],flag;
    struct cow{
        int father,son,cost;
    };
    cow tree[20001];
    bool cmp(cow x,cow y)
    {
        return x.cost>y.cost;
    }
    int find(int x)
    {
        if(fa[x]==x)
        return x;
        else
        return fa[x]=find(fa[x]);
    }
    void add(int x,int y)
    {
        fa[fa[x]]=fa[y];
    }
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
        fa[i]=i;
        for(int i=1;i<=m;i++)
        {
            scanf("%d%d%d",&tree[i].father,&tree[i].son,&tree[i].cost);
        }
        sort(tree+1,tree+1+m,cmp);
        for(int i=1;i<=m;i++)
        {
            if(find(tree[i].father)!=find(tree[i].son))
            {   
                ans1++;
                add(tree[i].father,tree[i].son);
                ans+=tree[i].cost;
            }    
        }
        if(ans1==n-1)
        {
            printf("%d",ans);
            return 0;
        }
        else
        printf("-1");
        return 0;
    }

    好题哉!!!

  • 相关阅读:
    C++设计模式-Bridge桥接模式
    解决VS2010打开Web页面时经常由于内存较低而导致VS2010自动关闭的问题
    Js继承小结
    MAC上的包管理利器
    Objective-C的hook方案(一): Method Swizzling
    OleContainer操作Excel以二进制方式读写数据库
    复制文件时,如何显示进度条(使用TFileStream一点一点读,或者使用BlockRead,并插入application.ProcessMessages)
    ADO异步查询显示进度条
    D2010 RTTI + Attribute 简单实现ORM
    Delphi默认窗体随想
  • 原文地址:https://www.cnblogs.com/qing1/p/11288394.html
Copyright © 2011-2022 走看看