• 第四次考试大整理


    第一题

    多重背包

    (backpack.cpp/c/pas)

    (1s/256M)

     

    题目描述

    提供一个背包,它最多能负载重量为W的物品。

    现在给出N种物品:对于第i类物品,一共有Ci件物品;对于每一件物品,重量为Wi,价值为Vi。

    找出一种装载方式使得背包中的物品总价值最大。

    输入格式(backpack.in)

    第一行两个整数N,W,代表物品的种类与背包的总负重。

    第2~N+1行,每行三个整数Wi, Vi, Ci,代表第i种物品的重量、价值与数量。

    (即同种背包拥有很多个)

    输出格式(backpack.out)

    仅一行,一个整数V,代表最大的总价值。

    样例输入

    3 9

    5 8 2

    3 6 2

    2 1 5

    样例输出

    14

    数据范围与限制

    1<=N<=20, 0<=W<=1000

    1<=Wi<=100, 0<=Vi<=100, 0<=Ci<=100

    ps:(老师说他的数据范围给错了???!!!exm?)

    超时代码情况:

    20个测试点,只得了55分,其他全部T……

    思路:

      改成类之后,仅仅是将背包的数量变多,多了许多相同价值的背包出来,

    那么,我们就可以将它转为01背包的方法,全部枚举一遍,可惜的是,超时

    代码如下:

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<cstdlib>
     7 #include<fstream> // 记住多include这一句
     8 #define M 2017
     9 
    10 using namespace std;
    11 
    12 int n,w;//物品的'种类' 与 背包的总负重
    13 int ans=0;
    14 int wi[M],vi[M],ci[M];//重量、价值与数量
    15 
    16 void dfs(int x,int noww,int nowv,int nownum)
    17 {
    18     if(x>n)//限制范围 
    19     {
    20         if(nowv>ans)
    21         {
    22             ans=nowv;//记录答案 
    23         }
    24         return;
    25     }
    26     
    27     if(nownum<ci[x])//如果这类的还有背包 
    28     {
    29         dfs(x,noww,nowv,nownum+1);//继续进行搜索 
    30     }
    31     else dfs(x+1,noww,nowv,1);    
    32     
    33     if(noww+wi[x]<=w)//若不超出总质量
    34     {
    35         if(nownum<ci[x])//如果这类的还有背包 
    36         {
    37             dfs(x,noww+wi[x],nowv+vi[x],nownum+1);//继续进行搜索 
    38         }
    39         else dfs(x+1,noww+wi[x],nowv+vi[x],1); 
    40     }
    41 }
    42 
    43 int main()
    44 {
    45     ifstream fin("backpack.in");
    46     ofstream fout("backpack.out");
    47 
    48     //scanf("%d%d",&n,&w);
    49     fin>>n>>w;
    50     for(int i=1;i<=n;i++)
    51     {
    52         //scanf("%d%d%d",&wi[i],&vi[i],&ci[i]);
    53         fin>>wi[i]>>vi[i]>>ci[i];
    54     }
    55     
    56     dfs(1,0,0,1);
    57     
    58     //printf("%d",ans);
    59     fout<<ans<<endl;
    60     
    61     return 0;
    62 }

    改进后思路:

    直接将单个单个的枚举改为for循环,因为同种背包的价值是相同的,

    所以不需要一个一个的枚举,仅仅需要改为“*”就可以!这一点是很重要的

    改成下面之后就并没有超时,

    代码如下:

     1 //backpack 
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<cstdlib>
     8 #include<fstream> // 记住多include这一句
     9 #define M 2017
    10 
    11 using namespace std;
    12 
    13 int n,w;//物品的'种类' 与 背包的总负重
    14 int ans=0;
    15 int wi[M],vi[M],ci[M];//重量、价值与数量
    16 
    17 void dfs(int x,int noww,int nowv)
    18 {
    19     if(x>n)//限制范围 
    20     {
    21         if(nowv>ans)
    22         {
    23             ans=nowv;//记录答案 
    24         }
    25         return;
    26     }
    27     for(int i=0;i<=ci[x]&&noww+wi[x]*i<=w;i++)
    28     {
    29         dfs(x+1,noww+wi[x]*i,nowv+vi[x]*i);
    30     }
    31 }
    32 
    33 int main()
    34 {
    35     ifstream fin("backpack.in");
    36     ofstream fout("backpack.out");
    37 
    38     //scanf("%d%d",&n,&w);
    39     fin>>n>>w;
    40     for(int i=1;i<=n;i++)
    41     {
    42         //scanf("%d%d%d",&wi[i],&vi[i],&ci[i]);
    43         fin>>wi[i]>>vi[i]>>ci[i];
    44     }
    45     
    46     dfs(1,0,0);
    47     
    48     //printf("%d",ans);
    49     fout<<ans<<endl;
    50     
    51     return 0;
    52 }

    第二题

    循环序列

    (circulate.cpp/c/pas)

    (1s/256M)

     

    题目描述

    Alice与Bob在玩游戏:

    Alice首先给出两个数X与Y(X<=Y);

    Bob则按顺序将X,X+1,X+2,…,Y-1,Y写成一个大数S。

    Alice最后将S首尾相连,让其围成一个圈。

    这时,Bob想知道,从S的开头出发,往后的第L到第R数字之和是多少。

    输入格式(circulate.in)

    第一行四个整数X,Y,L,R,代表Alice的两个数字和Bob想要知道的第L位到第R位的数字之和。

    输出格式(circulate.out)

    仅一行,一个整数M,代表第L位到第R位的数字之和。

    样例输入

    10 11 4 12

    样例输出

    7

    样例解释

    Bob将数字写成一行大数S = 1011;围成一个圈后,从第4位到第12位分别是1,1,0,1,1,1,0,1,1,它们的和是7.

    数据范围与限制

    对于50%的数据,L=1, X,Y,L,R<=1000;

    对于100%的数据,S的长度不大于10000,X,Y,L,R<=100000000.

    心得:

     这道题其实做的时候我并没有想出来啦,(因为没读懂题目的意思……)但是在老师讲过了之后,我感觉豁然开朗了

    代码+思路:

     1 #include <cstdio>
     2 #include <cstring>
     3 
     4 using namespace std;
     5 
     6 const int N = 1e5 + 6;
     7 
     8 int x, y, l, r;
     9 int n, a[N], s[N];
    10 int m, b[N];
    11 
    12 void work(int x, int y)
    13 {
    14     n = 0;                                        //记录最终一共是多少位的数 
    15     for(int i=x; i<=y; i++)                       //因为题目中说道这是有规律的(从小到大),依次进行枚举这些数 
    16     {
    17         m = 0;                                    //m用来记录当前数的位数是多少 
    18         for(int t=i; t; t/=10) b[++m] = t%10;     //将所有的数字都取出来 
    19         for(int t=m; t; t--) a[++n] = b[t];       //都放在最终(另外一个)的数组中,便于最终进行统计和 
    20     }
    21     
    22     s[0] = 0;                                     //前缀和数组 
    23     for(int i=1; i<=n; i++) s[i] = s[i-1] + a[i]; //进行前缀和处理 
    24 }
    25 
    26 int cal(int p)
    27 {
    28     if(p == 0) return 0;                          //是当数据是从头开始的情况吧 
    29 
    30     int g = (p-1) / n;                            //能够有多少个"区间" 
    31     int r = (p-1) % n + 1;                        //取出最后一个区间的最右边的前缀和 
    32 
    33     return s[n] * g + s[r];                       //直接返回正确答案 
    34 }
    35 
    36 int main()
    37 {
    38     freopen("circulate.in", "r", stdin);
    39     freopen("circulate.out", "w", stdout);
    40     
    41     scanf("%d%d", &x, &y);                        //输入的两个数字 
    42     scanf("%d%d", &l, &r);                        //区间范围 
    43 
    44     work(x, y);
    45     
    46     printf("%d
    ", cal(r) - cal(l-1));            //类似于前缀和?? 
    47     
    48     return 0;
    49 }

    第三题

    合并游戏

    merge.cpp/c/pas

    (1s/256M)

     

    题目描述

    Cindy和Dan在玩一个游戏。

    一开始Cindy想出了N个数,接着她把这N个数全部给了Dan。

    Dan得到这组数后,它会挑出3个数(如果不足3个则全部挑出)。Dan会把这几个数加起来变成一个数,然后再把这个数与剩下的数再放到一起。Dan会一直这样做,直到最后只剩下一个数。

    Cindy则会在旁边记下每次Dan得到的数,她把这些数加起来,作为本次游戏的得分。她想知道,对于一组数,Dan能得到的最大的得分是多少?

    输入格式

    第一行一个正整数N,代表这组数的个数;

    第二行N个正整数,代表这N个整数。

    输出格式

    一行一个整数,代表可能的最大得分。

    样例输入(merge.in)

    4

    3 1 5 6

    样例输出(merge.out)

    29

    样例解释

    Dan可以首先把(3,5,6)这三个数先合并起来,得到3 + 5 + 6 = 14; 接着他把剩下的两个数再合起来,得到1 + 14 = 15.这样,总得分是最大的 14 + 15 = 29.

    数据范围与限制

    对于50%的数据,N<=10

    对于100%的数据,N<=1000,所有数不大于1000

    拉呱:

    这道题可能是这三道题中最为简单的题了吧!这道题我A掉了,不过可惜的是,其他人并没有意识到这道题很简单,一直在研究第二题,……第二题我完全不会,就靠这个得的分

    所以一定要大体看一下题目的难易程度,然后再做题!

    思路:

    这道题目是求“最大”的得分,那么很显然这就是贪心,(贪最大的),而且不需要担心顺序在合并之后的改变,因为3个最大的数加起来一定就是剩余的数中最大的数,所以,不用合并一次就进行排序什么的,那么这道题就很简单了。

    因为是三个数三个数的进行合并,还有一个限制条件就是(如果不足三个就都挑出来)!这一点是非常重要的,所以他的结束条件就是当仅剩下3个数或者更加少的时候,直接进行合并,并且退出,输出答案。

    代码:

     1 //合并游戏//merge
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<cstdlib>
     8 #include<fstream>                             // 记住多include这一句
     9 #define M 1010
    10 
    11 using namespace std;
    12 
    13 int n,maxn=0;
    14 int ans=0,maxans=0;
    15 int qnum[M];
    16 
    17 void s(int nowsy,int nowans)                 //nowsy表示现在剩下的还有几个数 
    18 {
    19     if(nowsy==1||nowsy==2||nowsy==3)         //如果剩下的数都能够进行合并  
    20     {
    21         if(nowans+maxn>maxans)               //如果找到了最大的数值 
    22         {
    23             maxans=nowans+maxn;              //进行更新 
    24         }
    25         return ;
    26     }
    27     int x1=nowsy,x2=nowsy-1,x3=nowsy-2;
    28     qnum[x3]+=qnum[x1]+qnum[x2];             //将合并之后的数储存在x3中 
    29     ans+=qnum[x3];                           //更新答案 
    30     s(nowsy-2,ans);                          //继续递归下去 
    31 }
    32 
    33 int main()
    34 {
    35     ifstream fin("merge.in");
    36     ofstream fout("merge.out");
    37     
    38     //cin>>n;
    39     fin>>n;
    40     for(int i=1;i<=n;i++)
    41     {
    42         //cin>>qnum[i];
    43         fin>>qnum[i];
    44         maxn+=qnum[i];
    45 /*
    46 maxn是用来先记录下来这些书一共是多少,这样就可以在最后一次合并的时候,
    47 不用再次计算一次和的计算,我是感觉挺好用啦,但我并不知道你是怎么想的。 
    48 */ 
    49     }
    50 
    51     sort(qnum+1,qnum+1+n);                   //从小到大排序
    52     s(n,0);
    53 
    54     //cout<<maxans<<endl;
    55     fout<<maxans<<endl;
    56     
    57     return 0;
    58 }

     

    如果运气好也是错,那我倒愿意错上加错!

    ❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀❀

  • 相关阅读:
    查看Linux 系统串口信息
    解决:Web server failed to start. Port XXX was already in use
    SpringBoot集成WebSocket长连接实际应用详解
    EMQTT安装与使用
    mysql 分组查每组里创建时间最大的那条数据
    前端 获取本地时间,ios兼容
    SpringBoot:访问Mysql报错message from server: "Host 'XXXX' is blocked because of many connection errors
    Doker:dockercompose安装与操作
    Docker:docker安装操作InfluxDB时序数据库
    ASP.NET Core gRPC服务基础小例子
  • 原文地址:https://www.cnblogs.com/zxqxwnngztxx/p/6783291.html
Copyright © 2020-2023  润新知