2015年秋季大学先修课考试 解题报告

A:电话费

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

每到月初,小明都会收到中国移动的扣费通知。小明很喜欢打电话,每个月的电话费都很多,所以他去办了优惠套餐。假设小明这个月打了n次电话,小明可以选择不交其中s次电话的话费。小明算术能力很差,请帮帮他算一下这个月最少要交多少话费。

输入
输入包含两行:第一行为这个月打的电话数n,可以免费的电话数s,其中0 < s,n < 100;第二行包含n个实数,为每次电话的话费。每行中的二个数据之间均已空格间隔。
输出
输出只有一行,为小明这个月最少要交的话费(保留1位小数)。
样例输入
7 3
2.0 1.2 3.1 0.6 4.1 1.7 1.2
样例输出
4.7
#include<iostream>
using namespace std;
#include<cstdio>
#define N 101
int n,s;
double a[N];
#include<algorithm>
int main()
{
    scanf("%d%d",&n,&s);
    for(int i=1;i<=n;++i)
    {
        scanf("%lf",&a[i]);
    }
    sort(a+1,a+n+1);
    double sum=0;
    for(int i=1;i<=n-s;++i)
    sum+=a[i];
    printf("%0.1f",sum);
    return 0;
}
View Code

B:三个三位数的关系

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

将 1 到 9 这九个数字分成三个 3 位数,要求第一个 3 位数,正好是第二个 3 位数的一半,是第三个 3 位数的三分之一。问该如何分。

输入
没有输入。
输出
按第一个数从小到大输出满足条件的方案,每个方案占一行。方案中每个数之间用一个空格分开。
样例输入
没有输入。
样例输出
就不告诉大家答案了: )
#include<iostream>
using namespace std;
#include<cstdio>
bool judge(int a,int b,int c)
{
    int flag[10]={0};
    if(a<100||b<100||c<100) return false;
    for(int i=1;i<=3;++i)
    {
        int k=a%10;
        flag[k]++;
        if(flag[k]>1)
        return false;
        a/=10;
    }
    for(int i=1;i<=3;++i)
    {
        int k=b%10;
        flag[k]++;
        if(flag[k]>1)
        return false;
        b/=10;
    }
    for(int i=1;i<=3;++i)
    {
        int k=c%10;
        flag[k]++;
        if(flag[k]>1)
        return false;
        c/=10;
    }
    return true;
}
int main()
{
    int a;
    for(int i=300;i<=3000;++i)
    {
        if(i%6==0)
        {
            a=i/6;
            int b=2*a;
            int c=3*a;
            if(judge(a,b,c))
            {
                printf("%d %d %d\n",a,b,c);
            }
        }
    }
    return 0;
}
View Code

C:找到第一个遗漏的实验

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

小王是北京大学医学部的学生。一天,教授让小王帮忙做一系列的医学实验,实验是从1开始标号的,按照自然数顺序,最大不超过100个。每个实验会得到一张实验结果的表格,表格标号就是实验标号。一个月后,小王做完了所有的实验,但是粗心的小王同学遗失了几张实验结果的表格。小王只能把遗失的实验结果重新做一遍,这时,小王想要知道按照从1开始的自然数顺序里,第一个需要补充做的实验是哪个。

输入
第一行为一个整数n,代表未遗失的所有实验结果表格的数量 
第二行为n个整数,代表未遗失实验结果表格的标号
输出
输出为1行,输出按照自然数顺序,第一个需要重做的实验。
样例输入
5
2 1 5 10 11
样例输出
3
提示
第二行输入类似 1 2 3 4 5这样从1开始的连续的自然数时,代表第6个实验是第一个需要重做的实验,所以应该输出6。
#include<iostream>
using namespace std;
#include<cstdio>
int n;
bool flag[200]={0};
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        int x;
        scanf("%d",&x);
        flag[x]=true;
    }
    for(int i=1;i<=2*n;++i)
    if(!flag[i])
    {
        printf("%d\n",i);
        break;
    }
    return 0;
}
View Code

D:流感传染

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

有一批易感人群住在网格状的宿舍区内,宿舍区为n*n的矩阵,每个格点为一个房间,房间里可能住人,也可能空着。在第一天,有些房间里的人得了流感,以后每天,得流感的人会使其邻居传染上流感,(已经得病的不变),空房间不会传染。请输出第m天得流感的人数。

输入
第一行一个数字n,n不超过100,表示有n*n的宿舍房间。
接下来的n行,每行n个字符,’.’表示第一天该房间住着健康的人,’#’表示该房间空着,’@’表示第一天该房间住着得流感的人。
接下来的一行是一个整数m,m不超过100.
输出
输出第m天,得流感的人数
样例输入
5
....#
.#.@.
.#@..
#....
.....
4
样例输出
16
#include<iostream>
using namespace std;
#include<cstdio>
#define N 150
int jz[N][N];
#include<cstring>
int n,m;
struct node{
    int x,y;
};
int xx[]={0,0,1,-1};
int yy[]={1,-1,0,0};
node dl[N*N],dlhb[N*N];
int head=0,tail=0,head1=0,tail1=0;
int sum=0;
void input()
{
    scanf("%d",&n);
    for(int i=1;i<=n;++i)
    {
        char s[N];
        scanf("%s",s+1);
        for(int j=1;j<=n;++j)
        {
            if(s[j]=='.')
            jz[i][j]=1;
            if(s[j]=='@')
            {
                jz[i][j]=0;
                ++tail;
                dl[tail].x=i;
                dl[tail].y=j;
                sum++;
            }
            if(s[j]=='#')
            {
                jz[i][j]=1000000;
            }
        }
    }
    scanf("%d",&m);

}
void BFS()
{
    int t=1;
    while(1)
    {
      if(t==m) break;
      while(head<tail)
      {
        ++head;
        int x1=dl[head].x,y1=dl[head].y;
        for(int i=0;i<4;++i)
        {
            int x2=x1+xx[i],y2=y1+yy[i];
            if(x2>=1&&x2<=n&&y2>=1&&y2<=n&&jz[x2][y2]==1)
            {
                jz[x2][y2]=0;
                sum++;
                ++tail1;
                dlhb[tail1].x=x2;
                dlhb[tail1].y=y2;
            }
        }
         
       }
       t++;
       if(t==m) break;
       while(head1<tail1)
      {
        ++head1;
        int x1=dlhb[head1].x,y1=dlhb[head1].y;
        for(int i=0;i<4;++i)
        {
            int x2=x1+xx[i],y2=y1+yy[i];
            if(x2>=1&&x2<=n&&y2>=1&&y2<=n&&jz[x2][y2]==1)
            {
                jz[x2][y2]=0;
                sum++;
                ++tail;
                dl[tail].x=x2;
                dl[tail].y=y2;
            }
        }
         
       }
       t++;
       if(t==m) break;
    }
    printf("%d",sum);
}
int main()
{
    input();
    BFS();
    return 0;
}
View Code

E:字符串最大跨距

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

有三个字符串S,S1,S2,其中,S长度不超过300,S1和S2的长度不超过10。想检测S1和S2是否同时在S中出现,且S1位于S2的左边,并在S中互不交叉(即,S1的右边界点在S2的左边界点的左侧)。计算满足上述条件的最大跨距(即,最大间隔距离:最右边的S2的起始点与最左边的S1的终止点之间的字符数目)。如果没有满足条件的S1,S2存在,则输出-1。 

例如,S = "abcd123ab888efghij45ef67kl", S1="ab", S2="ef",其中,S1在S中出现了2次,S2也在S中出现了2次,最大跨距为:18。

输入
三个串:S1, S2, S3,其间以逗号间隔(注意,S1, S2, S3中均不含逗号和空格);
输出
S1和S2在S最大跨距;若在S中没有满足条件的S1和S2,则输出-1。
样例输入
abcd123ab888efghij45ef67kl,ab,ef
样例输出
18
#include<iostream>
using namespace std;
#include<cstdio>
#define N 1001
char ss[N+N];
char s[N+10],s1[N/2],s2[N/2];
#include<cstring>
int lens,len1=0,len2=0,lenss;
void input()
{
    scanf("%s",ss+1);
    lenss=strlen(ss+1);
    int i;
    for(i=1;i<lenss&&ss[i]!=',';++i)
    s[i]=ss[i];
    lens=i;
    for(i=i+1;ss[i]!=',';++i)
    {
        s1[++len1]=ss[i];
    }
    for(i=i+1;ss[i]!='\0';++i)
    s2[++len2]=ss[i];
}
bool judge_1(int l,int r)
{
    for(int i=1;l<=r&&i<=len1;++l,++i)
    if(s1[i]!=s[l]) return false;
    return true;
}
bool judge_2(int l,int r)
{
    for(int i=1;l<=r&&i<=len2;++l,++i)
    if(s2[i]!=s[l]) return false;
    return true;
}
void chuli()
{
    int ans[2]={0};
    for(int i=1;i<=lens-len1+1;++i)
    {
        if(judge_1(i,i+len1-1))
        {
            ans[0]=i+len1-1;
            break;
        }
    }
    for(int i=lens-len2+1;i>=1;--i)
    {
        if(judge_2(i,i+len2-1))
        {
            ans[1]=i;
            break;
        }
    }
    if(ans[0]==0||ans[1]==0||ans[0]>ans[1])
    printf("-1");
    else printf("%d",ans[1]-ans[0]-1);
}
int main()
{
    input();
    chuli();
    return 0;
}
View Code

F:最大零矩阵

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

有一个二位数组 m(< 100)行, n(< 100) 列,其元素为不大于100的非负整数。现要找元素值均为0的最大子二维数组,其中行相邻,列也相邻,行数与列数之积最大(即,所含0元素最多),输出该最大积。例如: 

2  5  0  0  8  11  15 
3  0  0  0  0  12  16 
7  0  0  0  0  13  17 
8  0  0  7  1  14  18 
4  0  0  0  0  0   0 
6  0  0  0  0  0   0 

这是6行,7列构成的二维数组,其中:由第4~5行(最后2行),第1~6列(最后6列)构成的子数组最大,共有12个0元素,因此,应该输出 12。其它情况下的子数组都不多于12个0元素,例如,第1~5行与第1~2列构成子数组为第二大数组,含有10个0元素。 

输入
第一行,m 和 n 的值,以空格间隔,m 和 n 均为 不大于 100 的正整数 
之后,共 m 行,每行共 n 个元素,其间用空格间格。
输出
输出,最大零元素子二维数组所含的 0 元素个数,如果没有0元素,则输出0。
样例输入
6 7
2  5  0  0  8  11  15
3  0  0  0  0  12  16
7  0  0  0  0  13  17
8  0  0  7  1  14  18
4  0  0  0  0  0   0
6  0  0  0  0  0   0
样例输出
12
#include<iostream>
using namespace std;
#include<cstdio>
#define N 150
int f[N][N];
int h[N],l[N],r[N];
#include<cstring>
int n,m;
int ans=-1;
bool flag=false;
void input()
{
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;++i)
      for(int j=1;j<=n;++j)
      {
          scanf("%d",&f[i][j]);
          if(f[i][j]==0)
          flag=true;
      }
}
void chuli()
{
    memset(h,0,sizeof(h));
    for(int i=1;i<=m;++i)
    {
        int l1,l2;
        for(int j=1;j<=n;++j)
        if(f[i][j]==0)
        h[j]++;
        else h[j]=0;
        for(int j=2;j<=n;++j)
        {
            if(f[i][j]!=0) continue;
            l1=j;
            while(l1>1&&h[l1]>=h[j])
            l1--;
            l[j]=j-l1-1;
        }
        for(int j=n-1;j>=1;--j)
        {
            if(f[i][j]!=0) continue;
            l2=j;
            while(l2<n&&h[l2]>=h[j])
            l2++;
            r[j]=l2-j-1;
        }
        for(int j=1;j<=n;++j)
          ans=max(ans,h[j]*(l[j]+r[j]+1));
    }
    
}
int main()
{
    input();
    if(!flag)
    {
        cout<<0<<endl;
    }
    else 
    {
        chuli();
        printf("%d",ans);
    }
    return 0;
}
View Code

 

G:实数加法

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

求2个实数相加的和。

输入输出中出现的实数都有如下的形式: P1P2...Pi.Q1Q2...Qj。对于整数部分,P1P2...Pi是一个非负整数;对于小数部分,至少有一位且最后一位Qj不等于0。

输入
2行,分别是两个加数。每个加数不超过100个字符。
输出
一行输出是相应的和。数据保证一定是一个小数部分不为0的实数。
样例输入
0.111111111111111111111111111111
0.111111111111111111111111111111
样例输出
0.222222222222222222222222222222
代码:
#include<iostream>
using namespace std;
#include<cstdio>
#include<cstring>
#define N 150000
int lenint1[N],lenf1[N],lenint2[N],lenf2[N];
int intans[N],lenint,floatans[N],lenfloat;
int lenia,lenfa,lenib,lenfb;
char ss[N];
void input()
{
    scanf("%s",ss+1);
    int lens=strlen(ss+1);
    int i;
    for(i=1;ss[i]!='.';++i);/*输入的时候,把小数位与整数位分别储存,进行计算*/
    lenia=0;
    for(int j=i-1;j>=1;--j)
    lenint1[++lenia]=ss[j]-'0';/*小数与整数都要倒序储存*/
    lenfa=0;
    for(int j=lens;j>=i+1;--j)
    lenf1[++lenfa]=ss[j]-'0';
    memset(ss,0,sizeof(ss));
    scanf("%s",ss+1);
    lens=strlen(ss+1);
    for(i=1;ss[i]!='.';++i);
    lenib=0;
    for(int j=i-1;j>=1;--j)
    lenint2[++lenib]=ss[j]-'0';
    lenfb=0;
    for(int j=lens;j>=i+1;--j)
    lenf2[++lenfb]=ss[j]-'0';
    if(lenfb<lenfa)/*特别注意这个地方:小数的加法不能直接像整数一样加,因为整数是低位对齐加,而小数必须是高位对齐加*/
    {
        int k=lenfa-lenfb;/*这就是对齐的过程,在位数少后面补上0*/
        for(int i=lenfb;i>=1;--i)
        lenf2[i+k]=lenf2[i];
        for(int i=1;i<=k;++i)
        lenf2[i]=0;
        lenfb=lenfa;
    }
    else     if(lenfa<lenfb)
    {
        int k=lenfb-lenfa;
        for(int i=lenfa;i>=1;--i)
        lenf1[i+k]=lenf1[i];
        for(int i=1;i<=k;++i)
        lenf1[i]=0;
        lenfa=lenfb;
    }
}
void add_1()
{
    lenint=1;
    while(lenint<=lenia||lenint<=lenib)
    {/*注意这个地方必须是+=才可以,保存之前的进位*/
        intans[lenint]+=lenint1[lenint]+lenint2[lenint];
        intans[lenint+1]+=intans[lenint]/10;
        intans[lenint]%=10;
        lenint++;
    }
    if(intans[lenint]==0) 
    lenint--;
}
void add_2()
{
    lenfloat=1;
    while(lenfloat<=lenfa||lenfloat<=lenfb)
    {
        floatans[lenfloat]+=lenf1[lenfloat]+lenf2[lenfloat];
        floatans[lenfloat+1]+=floatans[lenfloat]/10;
        floatans[lenfloat]%=10;
        lenfloat++;
    }
    if(floatans[lenfloat]==0) 
    lenfloat--;
}
void out()
{
    if(lenfloat>max(lenfa,lenfb))/*注意二:判断小数是否向整数位进位,也就是总位数加长了*/
    {
        int k=floatans[lenfloat];
        lenfloat--;
        int m=1;
        intans[m]+=k;
        while(intans[m]>=10)
        {
            intans[m+1]++;
            intans[m]%=10;
            m++;
        }
        if(intans[lenint+1]!=0) lenint++;/*处理进位的过程*/
    for(int i=lenint;i>=1;--i)
    printf("%d",intans[i]);
    printf(".");
    int l=1;
    while(floatans[l]==0) l++;/*关键:删除小数位后面多余的0*/
    for(int j=lenfloat;j>=l;--j)
    printf("%d",floatans[j]);
    }
    else {
    for(int i=lenint;i>=1;--i)
    printf("%d",intans[i]);
    printf(".");
    int l=1;
    while(floatans[l]==0) l++;
    for(int j=lenfloat;j>=l;--j)
    printf("%d",floatans[j]);
    }
    return;
}
int main()
{
    input();
    add_1();
    add_2();
    out();
    return 0;
}
View Code

 

H:幼儿园分糖果

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述

新年将至,幼儿园的老师们为小朋友们准备了各种各样的糖果。不同的小朋友所喜欢的糖果可能是不同的,为了让更多的小朋友得到他/她喜爱的糖果,幼儿园的老师们对小朋友们的“糖果偏好”(即哪位小朋友喜欢哪几种糖果)进行了统计。 
   
    现已知老师们共准备了F种糖果,准备为幼儿园里的N位小朋友分配糖果。同上所述,我们假设: 
(1)每位小朋友只会接受自己喜欢的糖果,不接受自己不喜欢的糖果; 
(2)每种糖果只能分给某一位小朋友(即:一旦某种糖果分给某位小朋友,则其他小朋友就不能再被分配到该种糖果); 
(3)我们不保证所有小朋友都能获得糖果; 
(4)每个小朋友喜欢哪种糖果将在输入数据中给出。 

    请你构造一个程序,帮助老师们分配糖果,以使得在上述条件下,老师们能够将现有糖果分配给最多的小朋友。请输出可分到糖果的小朋友的最多的人数。

输入
第1行为两个整数:N 和 F,以空格隔开。其中,N(1≤ N ≤ 20)表示小朋友的总人数;F(1 ≤ F ≤ 20)表示糖果的总种数(糖果种类分别用整数1,2,3,...,F进行编号)。 

接下来有N行,每行包含多个以空格隔开的整数;其中,第一个整数m,表示某位小朋友所喜爱的糖果的种数,其后的m个整数,表示该小朋友所喜爱的糖果种类的编号序列。 
例如:若某行的输入为“3 1 2 3”,则表示该位小朋友共喜欢3种类型的糖果,其糖果类型编号分别为“1”“2”“3”。
输出
仅一行,即在上述输入条件下,能分到糖果的小朋友的人数的最大值。
样例输入
4 3
2 1 2
2 2 3
2 1 3
2 1 3
样例输出
3
代码:
/*部分数据不过,需要用二分图匹配*/
#include<iostream>
using namespace std;
#include<cstdio>
#define N 21
#include<algorithm>
struct Child{
    int sum[N];
    bool operator <(const Child &p)
    const{return sum[0]<p.sum[0];}
}child[N];
bool cab[N]={0};
int n,f;
void input()
{
    scanf("%d%d",&n,&f);
    for(int i=1;i<=n;++i)
    {
        int m;
        scanf("%d",&m);
        for(int j=1;j<=m;++j)
        {
            scanf("%d",&child[i].sum[j]);
        }
        child[i].sum[0]=m;
     } 
}
int sum=0;
void chuli()
{
    for(int i=1;i<=n;++i)
    {
        for(int j=1;j<=child[i].sum[0];++j)
        {
            if(!cab[child[i].sum[j]])
            {
                cab[child[i].sum[j]]=true;
                sum++;
                break;
            }
        }
    }
}
int main()
{
    input();
    sort(child+1,child+n+1);
    chuli();
    printf("%d\n",sum);
    return 0;
}
View Code

I:还是采药问题

总时间限制: 
1000ms
 
内存限制: 
65536kB
描述
辰辰是个天资聪颖的孩子,他的梦想是成为世界上最伟大的医师。为此,他想拜附近最有威望的医师为师。医师为了判断他的资质,给他出了一个难题。医师把他带到一个到处都是草药的山洞里对他说:“孩子,这个山洞里有一些不同的草药,采每一株都需要一些时间,每一株也有它自身的价值。我会给你一段时间,在这段时间里,你可以采到一些草药。如果你是一个聪明的孩子,你应该可以让采到的草药的总价值最大。” 如果你是辰辰,你能完成这个任务吗? 
输入
输入第一行有两个整数T(1 <= T <= 1000)和M(1 <= M <= 100),用一个空格隔开,T代表总共能够用来采药的时间,M代表山洞里的草药的数目。接下来的M行每行包括两个在1到100之间(包括1和100)的整数,分别表示采摘某株草药的时间和这株草药的价值。
输出
输出包括一行,这一行只包含一个整数,表示在规定的时间内,可以采到的草药的最大总价值。
样例输入
70 3
71 100
69 1
1 2
样例输出
3
#include<iostream>
using namespace std;
#include<cstdio>
#define T 1201
int f[T];
int tim[T],val[T],t,m;
void input()
{
    scanf("%d%d",&t,&m);
    for(int i=1;i<=m;++i)
    scanf("%d%d",&tim[i],&val[i]);
}
void DP()
{
    for(int i=1;i<=m;++i)
      for(int j=t;j>=tim[i];--j)
      f[j]=max(f[j],f[j-tim[i]]+val[i]);
    cout<<f[t]<<endl;
    return ;
}
int main()
{
    input();
    DP();
    return 0;
}
View Code

 

 

 
 
posted @ 2016-04-14 19:18  csgc0131123  阅读(1023)  评论(0编辑  收藏  举报