程序设计基础II(实验1-6)

发布于:2024-12-23 ⋅ 阅读:(16) ⋅ 点赞:(0)

实验1 结构体与共用体

7-1 检查宿舍卫生

不知道是从哪个学校开始兴起的还是哪个领导的决定,学校里每周都要检查宿舍卫生!大家发现没有,检查宿舍卫生是件很奇葩的事情,它剥削了每件物品的意义:垃圾桶里不能有垃圾,挂钩上不能挂东西,桌子上不能放东西,床上不能躺人!!假设检查卫生分为五项成绩:垃圾桶得分、挂钩得分、桌子得分、床铺得分和窗台得分。每项满分20分,总分满分为100分。按照计算机学院奇葩的规定,宿舍成绩在85分以下就要算作不合格。某天,宿管阿姨给了你一个检查完宿舍的打分表,让你帮忙统计下有多少个宿舍没有达到85分(等于85分是可以的),并且统计成绩最高分。

输入格式:
第一行为一个整数 n (0 < n <= 100),代表你要统计的宿舍的总数,接下来 n 行每行为 5 个整数,代表宿舍五项成绩的得分。

输出格式:
输出只有一行,由一个空格分隔的两个整数:总分不合格的宿舍数和宿舍总分最高分,如果最高分仍小于85分,则输出为不合格的宿舍数和“No”(不包含引号)。

输入样例:
5
1 2 3 4 5
10 20 10 20 20
20 20 20 20 20
15 15 15 20 20
10 10 10 10 10

输出样例:
3 100

#include <stdio.h>
int main()
{
    int n;int i,j,a,b,c,d,e;
    int max=-1,k=0;
    int m[100];
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)//n行
        {
         scanf("%d %d %d %d %d",&a,&b,&c,&d,&e);
         m[i]=a+b+c+d+e;
        }
        
        max=-1;k=0;
        for(i=1;i<=n;i++)
        {
            if(m[i]>max)
            {
               max=m[i];
            }
            if(m[i]<85)//不合格
                k++;
        }
    }
    
     if(max<85) printf("%d No",n);
    else printf("%d %d",k,max);
    return 0;
}

7-2 小 I 的小姐姐

小 I 去天津玩啦,一路上,他跟他的同学发生了许多有趣的事。

当他们路过天津外国语学院时,他发现了许多小姐姐,他眼花缭乱,甚至不知道该去找哪个小姐姐聊天。

怎么办怎么办!

于是他想到了你,他拍了一张照片给你,你发现照片里一共有 n 个小姐姐(序号从 0 到 n - 1),每个小姐姐都有自己的风格,可以按特征划分出 3 个特征值 w1 , w2 , w3 ,你知道小 I 特别喜欢 w1 特征值高的小姐姐,不太看重 w3 ,于是你对于每个特征都赋予一个权重,分别对应为0.7 0.2 0.1,你能帮小 I 找出来他发来的这张照片里他最喜欢的小姐姐吗?

输入格式:
第一行给出一个整数 n (n <= 1000) ,之后有 n 行数。

每行数有三个整数 w1, w2, w3,表示三个特征值。

不存在权值和相等的情况。

输出格式:
输出n 个小姐姐中权值和最高的序号。

输入样例:
3
1 5 10
5 1 10
10 5 1

输出样例:
2

#include <stdio.h>
int a[10000000];
int main()
{
    int n;
    scanf("%d",&n);
    int i=0;int w1,w2,w3;
    int result=0,max=-1,k=0;
    for(i=0;i<n;i++)
    {
        scanf("%d %d %d",&w1,&w2,&w3);
        result=w1*0.7+w2*0.2+w3*0.1;
        if(result>max)
        {
            max=result;
            k=i;
        }
        
    }
    
    printf("%d",k);
    return 0;
}

7-3 选票统计

某校学生会主席由全校学生投票选举产生,共有m名候选人报名参选,编号为1到m(0<m<1000),全校有n名学生(0<n<30000),每人都可以投票。但每人只能投一票,每票只能选1名候选人。请你设计一个程序能够统计出哪个候选人得票最高,得了多少票。不会出现得票数相同的情况。

输入格式:
第一行输入候选人数m和学生数n,以空格分开;

下面依次输入每个学生所选的候选人的编号。

输出格式:
第一行输出得票最多的候选人编号;

第二行输出该候选人所得的票数。

输入样例:
3 10
1 2 3 2 3 1 2 3 1 3

输出样例:
3
4

#include <stdio.h>
int a[10000],b[1000000];
int main()
{
    int m,n;
    scanf("%d %d",&m,&n);
    int i=0,max=-1,k=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
        b[a[i]]++;
    }
    
    for(i=1;i<=m;i++)
    {
        if(b[i]>max)
        {
            max=b[i];
            k=i;
            
        }
    }
    
    printf("%d\n%d\n",k,max);
    return 0;
}

7-4 小 I 选宾馆

小 I 去天津玩啦,一路上,他跟他的同学发生了许多有趣的事。

到了晚上了,小 I 跟他的同学们要选一个宾馆住下了。但是形形色色的宾馆让小 I 不知所措。

对于一个宾馆来说,有许多特征,比如「价格」、「舒适度」。小I会对每个特征都有一个满意度。

小I会选择出满意度更高一些的宾馆。

其中,「价格」对于小 I 来说是最重要的,其次是「舒适度」。

如果有两个宾馆,如果对「价格」的满意度相同,那么根据「舒适度」进行选择;如果有多个宾馆条件相同,输出编号最小的宾馆。

小 I 现在处于水深火热之中,因为他们面对一堆宾馆不知所措,他想到了会编程的你,如果你不帮他选出来,他可能就会露宿街头了QAQ~

你能帮他按照他的意愿找到小I最满意的宾馆吗?

输入格式:
给出 n (n <= 5000) 代表 n 个宾馆(编号从 1 - n),随后有 n 行数据。

每行数据有两个整数,分别代表小I对「价格」、「舒适度」的满意程度,数值越大满意程度越高,满意度的范围从0 - 5000。

输出格式:
输出按照描述的条件中小I最满意的宾馆编号,如果有多个宾馆条件相同,输出编号最小的宾馆。

输入样例:
4
0 1
1 0
1 1
1 0

输出样例:
3

#include<stdio.h>
struct num
{
    int price;
    int comfort;
}a[5000];
int main()
{
    int i,n,m=0;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf("%d %d",&a[i].price,&a[i].comfort);
    }
    for(i=0;i<n;i++)
    {
        if(a[i].price>a[m].price)
        {
            m=i;
        }
        else if(a[i].price==a[m].price)
        {
            if(a[i].comfort>a[m].comfort)
            {
                m=i;
            }
        }
    }
    printf("%d\n",m+1);
    return 0;
}

7-5 小鑫の日常系列故事(十)——排名次

小鑫在来到SDUT之后,经过十分刻苦的学习和努力终于进入了ACM集训队。很快又一次ACM集训队的选拔就要开始了,集训队员们又忙碌了起来。他也十分幸运的被学长抓来当苦力。 o(∩_∩)o
这次学长给他分配的任务是写一个自动排名的程序,我们知道当选拔赛结束的时候,每一个参与选拔的同学都会有一个自己的分数。而集训队需要根据大家的分数排名来决定谁能够进入集训队,这个任务就落在了小鑫身上。
你能帮小鑫来完成这个程序么?

输入格式:
输入的第一行为n ( 0<n<=50) ;

之后给出n 行,每行为一个人名和ta所得到的分数。保证没有相同的分数。
人名为英文单词,长度不超过10。

输出格式:
输出为n行,每行一个人名与他的得分。每一行最后没有多余的空格。

具体输出格式见样例。

输入样例:
3
Dan 10
John 50
Danny 30

输出样例:
John 50
Danny 30
Dan 10

#include <stdio.h>
struct pai
{
    int fen;
    char name[10000];
}a[10000],t;

int main()
{
    int n,i,j=0;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf("%s %d",a[i].name,&a[i].fen);
    }
    
    for(i=0;i<n-1;i++)
    {
        for(j=0;j<n-1-i;j++)
        {
            if(a[j].fen<a[j+1].fen)
            {
                t=a[j+1];
                a[j+1]=a[j];
                a[j]=t;
            }
        }
    }
    
    for(i=0;i<n;i++)
    {
        printf("%s %d\n",a[i].name,a[i].fen);
    }
    return 0;
}

7-6 最终排名

第四届山东理工大学ACM网络编程擂台赛比赛完后需要产生一个最终排名,排名按照题数多少来决定。但是有太多的队伍参与,手动计算排名已经不能满足比赛的需求。现在有一份名单记录各个队伍的ID和做出的题目数,需要你写一个程序,产生最终的排名。

为了简化题目,这里的排名规则为:做出题目数量多的队伍排在前面,如果题数相等,保持输入时的相对顺序不要改变。

输入格式:
第一行有一个正整数N(1 < N ≤ 10000),表示队伍数量。

接下来N 行包含两个整数,1 ≤ ID ≤ 10^7, 0 ≤ M ≤ 100。ID为队伍的编号,M为做出的题数。

输出格式:
输出包含N行;

第i行有两个整数,ID和M表示排在第i位的队伍的ID和做出的题数。

输入样例:
8
1 2
16 3
11 2
20 3
3 5
26 4
7 1
22 4

输出样例:
3 5
26 4
22 4
16 3
20 3
1 2
11 2
7 1

#include <stdio.h>
struct pai
{
    int id;
    int fen;
}a[10000],t;
int main()
{
    int n;int i,j=0;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf("%d %d",&a[i].id,&a[i].fen);
    }
    for(i=0;i<n-1;i++)
    {
        for(j=0;j<n-1-i;j++)
        {
            if(a[j].fen<a[j+1].fen)
            {
                t=a[j+1];
                a[j+1]=a[j];
                a[j]=t;
            }
        }
    }
    
    for(i=0;i<n;i++)
    {
        printf("%d %d\n",a[i].id,a[i].fen);
    }
    
    return 0;
}

7-7 选夫婿1

倾国倾城的大家闺秀潘小姐要选夫婿啦!武林中各门各派,武林外各大户人家,闻讯纷纷前来,强势围观。前来参与竞选的男生藏龙卧虎,高手云集,才子遍布,帅哥纷纭,更不乏富二代,官二代,可谓声势空前。

每个人参与竞选的帅哥除了进行一段激情洋溢的求婚演讲以外,还要报上自己姓名、身高和体重,以及个人简历。最后再进行文武选拔,最后夺魁者方能得到潘小姐的芳心。

潘小姐不爱名利,只看人,第一关就是身高和体重要合格,即必须在其要求的范围内,否则直接排除在外,不允许参加下一轮的选拔。

作为一个程序员,你没有钱也没有权,擅长的也就是编程了。潘小姐也发现了这一点,所以把首轮根据身高体重进行选拔的任务交给了你,如果完成的好,你可以直接进入下一轮选拔,你笑了。

输入格式:
潘小姐给你了所有报名男生的信息。

输入数据的第一行是一个正整数N (0 < N < 1000)。

之后N 行数据,每行包含三部分,用空格隔开。第一部分是报名者的姓名name(长度小于20的字符串),然后是整数身高h(0 < h < 300),第三部分是整数体重w (0 < w < 200)。

最后一行是四个整数a,b,c,d.表示身高的合格范围是[a,b],体重的合格范围是[c,d](0 < a < b < 200, 0 < c < d < 300)。

输出格式:
你需要把合格的男生信息按照身高从低到高输出,格式跟输入一样,也是每行三个信息,共N行,如果身高相同则按体重从轻到重输出,若没有合格人选则输出No,具体格式见样例。

输入样例:
8
武大郎 70 40
西门庆 180 70
李逵 160 150
燕青 175 69
鲁智深 180 100
武松 180 75
小泉纯一狼 30 20
孙二娘 169 60
165 190 60 90

输出样例:
孙二娘 169 60
燕青 175 69
西门庆 180 70
武松 180 75

#include <stdio.h>
struct pai
{
    char name[1000];
    int sg,tz;
}a[10050],t;
int main()
{
    int n,b,c,d,e;
    scanf("%d",&n);
    int i,j=0,m=0;
    for(i=0;i<n;i++)
    {
        scanf("%s %d %d",a[i].name,&a[i].sg,&a[i].tz);
    }
    scanf("%d %d %d %d",&b,&c,&d,&e);
    
    for(i=0;i<n;i++)
    {
        if(a[i].sg>=b&&a[i].sg<=c&&a[i].tz>=d&&a[i].tz<=e)
        {
            for(i=0;i<n-1;i++)
            {
                for(j=0;j<n-1-i;j++)
                {
                    if(a[j].sg>a[j+1].sg)
                    {
                        t=a[j+1];
                        a[j+1]=a[j];
                        a[j]=t;
                    }
                    
                    if(a[j].sg==a[j+1].sg)
                    {
                        if(a[j].tz>a[j+1].tz)
                        {
                            t=a[j+1];
                            a[j+1]=a[j];
                            a[j]=t;
                        }
                    }
                }
            }
            m++;
        }
    }
    if(m==0)printf("No");
    
    for(i=0;i<n;i++)
    {
        if(a[i].sg>=b&&a[i].sg<=c&&a[i].tz>=d&&a[i].tz<=e)
            printf("%s %d %d\n",a[i].name,a[i].sg,a[i].tz);
    }
    return 0;
}

7-8 老–质价比

给出n件物品,每件物品有质量和价格两种属性。你要做的是按质量升序排序,若质量相同则按价格降序排序。

输入格式:
第一行输入一个正整数n(1<=n && n <= 100),代表有n件物品。

接下来的一行有n个正整数Wi(1<= Wi && Wi <= 10000),代表每件物品的质量。

再接下来的一行有n个正整数Pi(1 <= Pi && Pi <= 10000),代表每件物品的价格。

输出格式:
输出n行,每行两个数Wi,Pi。顺序为题目描述所要求。

输入样例:
3
1 2 2
3 2 3

输出样例:
1 3
2 3
2 2

#include <stdio.h>
struct pai
{
    int jg;int zl;
}a[10000],t;
int main()
{
    int n;int i,j=0;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i].zl);
        
    }
    
    for(i=0;i<n;i++)
    {
        scanf("%d",&a[i].jg);
        
    }
    
    for(i=0;i<n-1;i++)
    {
        for(j=0;j<n-1-i;j++)
        {
            if(a[j].zl>a[j+1].zl)
            {
                t=a[j+1];
                a[j+1]=a[j];
                a[j]=t;
            }
            
            else if(a[j].zl==a[j+1].zl)
            {
                if(a[j].jg<a[j+1].jg)
                {
                  t=a[j+1];
                    a[j+1]=a[j];
                    a[j]=t;
                }
            }
        }
    }
    
    
    for(i=0;i<n;i++)
    {
        printf("%d %d\n",a[i].zl,a[i].jg);
    }
    
    return 0;
}

7-9 共用体练习

给定n和m,接下来有n个描述,每个描述包含一个类型标志和一组相应的数据。

类型标志共3种:INT DOUBLE STRING,然后对应一组相应的数据。

紧接着有m个询问,每个询问仅包含一个整数x,要求输出第x个描述对应的数据(STRING类型保证不含空格,每组对应STRING数据不会超过19个字符)。

输入格式:
输入的第一行为两个整数,n和m (n<=100000, m<=100000 ), 分别代表描述的个数和询问的个数。

接下来为 n 行描述;

最后为m行询问,具体格式见样例输入输出。

输出格式:
对于每个询问,输出对应的结果,注意:浮点数保留两位小数。

输入样例:
5 4
INT 456
DOUBLE 123.56
DOUBLE 0.476
STRING welcomeToC
STRING LemonTree
0
1
2
4

输出样例:
456
123.56
0.48
LemonTree

提示:
必须使用共用体完成

#include <stdio.h>
union pai
{
    int a;
    double b;
    char c[25];
}a[10000000],t[1000000];
int main()
{
    int m,n;int i=0;
    scanf("%d %d",&m,&n);
    for(i=0;i<m;i++)
    {
        scanf("%s",a[i].c);
        if(a[i].c[0]=='I')
            scanf("%d",&t[i].a);
        else if(a[i].c[0]=='D')
            scanf("%lf",&t[i].b);
        else if(a[i].c[0]=='S')
            scanf("%s",t[i].c);
    }
    int x;
    for(i=0;i<n;i++)
    {
        scanf("%d",&x);
        if(a[x].c[0]=='I')
            printf("%d\n",t[x].a);
        else if(a[x].c[0]=='D')
            printf("%.2lf\n",t[x].b);
        else if(a[x].c[0]=='S')
            printf("%s\n",t[x].c);
    }
    return 0;
    
}

7-10 简单枚举类型——植物与颜色

请定义具有red, orange, yellow, green, blue, violet六种颜色的枚举类型color,根据输入的颜色名称,输出以下六种植物花朵的颜色:
Rose(red), Poppies(orange), Sunflower(yellow), Grass(green), Bluebells(blue), Violets(violet)。如果输入的颜色名称不在枚举类型color中,例如输入purple,请输出I don’t know about the color purple.

输入格式:
第一行输入一个n, 代表有n 组询问。( 1 <= n <= 10)

接下来的n行, 每行有一个字符串代表颜色名称,颜色名称最多30个字符。

输出格式:
输出n 行。

每行输出对应颜色的植物名称。

例如:Bluebells are blue. 如果输入的颜色名称不在枚举类型color中,例如purple, 请输出I don’t know about the color purple.

输入样例:
3
blue
yellow
purple
AI助手
输出样例:
Bluebells are blue.
Sunflower are yellow.
I don’t know about the color purple.
AI助手
提示:
请用枚举类型实现

#include <stdio.h>
#include <string.h>
enum color{red,orange,yellow,green,blue,violet,no}w;

  int main()
  {
     char a[31];
     int n;
      scanf("%d",&n);
      getchar();
      while(n--)
      {
          gets(a);
         if(strcmp(a,"red")==0)
            w=red;
           else if(strcmp(a,"orange")==0)
            w=orange;
            else if(strcmp(a,"yellow")==0)
            w=yellow;
            else if(strcmp(a,"green")==0)
            w=green;
            else if(strcmp(a,"blue")==0)
            w=blue;
            else if(strcmp(a,"violet")==0)
            w=violet;
            else w = no;
            switch(w)
            {
                case red:printf("Rose are red.\n");break;
                case orange:printf("Poppies are orange.\n");break;
                case yellow:printf("Sunflower are yellow.\n");break;
                case green:printf("Grass are green.\n");break;
                case blue:printf("Bluebells are blue.\n");break;
                case violet:printf("Violets are violet.\n");break;
                case no:
                    printf("I don't know about the color %s.\n",a);
            }
     }
      return 0;
  }

实验2 链表

7-1 数据结构实验之链表一:顺序建立链表

输入N个整数,按照输入的顺序建立单链表存储,并遍历所建立的单链表,输出这些数据。

输入格式:
第一行输入整数的个数N(1 <= N <= 100000)。

第二行依次输入每个整数。

输出格式:
输出这组整数。

输入样例:
8
12 56 4 6 55 15 33 62

输出样例:
12 56 4 6 55 15 33 62

#include <stdio.h>
int a[10000000];
int main()
{
    int n;
    scanf("%d",&n);
    int i=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    
    for(i=1;i<=n;i++)
    {
        if(i==1)
            printf("%d",a[i]);
        else printf(" %d",a[i]);
    }
    return 0;
}

7-2 数据结构实验之链表二:逆序建立链表

输入整数个数N,再输入N个整数,按照这些整数输入的相反顺序建立单链表,并依次遍历输出单链表的数据。

输入格式:
第一行输入整数N(1<=N<=100000)。

第二行依次输入N个整数,逆序建立单链表。

输出格式:
依次输出单链表所存放的数据。

输入样例:
10
11 3 5 27 9 12 43 16 84 22

输出样例:
22 84 16 43 12 9 27 5 3 11

#include <stdio.h>
int a[100000000090];
int main()
{
    int n;
    scanf("%d",&n);
    int i=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    
    for(i=n;i>=1;i--)
    {
        if(i==1)
            printf("%d",a[i]);
        else printf("%d ",a[i]);
        
    }
    return 0;
}

7-3 数据结构实验之链表三:链表的逆置

输入多个整数,以-1作为结束标志,顺序建立一个带头结点的单链表,之后对该单链表的数据进行逆置,并输出逆置后的单链表数据。

输入格式:
输入多个整数,以-1作为结束标志。(整数个数不超过100000,不低于1)

输出格式:
输出逆置后的单链表数据。

输入样例:
12 56 4 6 55 15 33 62 -1

输出样例:
62 33 15 55 6 4 56 12

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*next;
};

int main()
{
    int num;
    struct node*head=(struct node*)malloc(sizeof(struct node));
    head->next=NULL;
    while(scanf("%d",&num)!=EOF&&num!=-1)
    {
        struct node*p=(struct node*)malloc(sizeof(struct node));
        p->next=NULL;
        p->data=num;
        
        p->next=head->next;
        head->next=p;
    }
    
    struct node*r=head->next;
    while(r)
    {
        if(r->next==NULL)
            printf("%d",r->data);
        else printf("%d ",r->data);
        r=r->next;
    }
    return 0;
}

7-4 数据结构实验之链表四:有序链表的归并

分别输入两个有序的整数序列(分别包含M和N个数据),建立两个有序的单链表,将这两个有序单链表合并成为一个大的有序单链表,并依次输出合并后的单链表数据。

输入格式:
第一行输入M与N的值。(1 <= M <=100000, 1 <= N <= 100000)

第二行依次输入M个有序的整数。

第三行依次输入N个有序的整数。

输出格式:
输出合并后的单链表所包含的M+N个有序的整数。

输入样例:
6 5
1 23 26 45 66 99
14 21 28 50 100

输出样例:
1 14 21 23 26 28 45 50 66 99 100

#include <stdio.h>
#include <stdlib.h>

struct node
{
    int data;
    struct node*next;
};
int main()
{
    int m,n;int i=0;
    scanf("%d %d",&m,&n);
    struct node *head1,*head2,*tail1;
        head1=(struct node*)malloc(sizeof(struct node));
    head1->next=NULL;
    tail1=head1;
    for(i=1;i<=m;i++)
    {
        struct node*p1;
        p1=(struct node*)malloc(sizeof(struct node));
        
        scanf("%d",&p1->data);
        
         p1->next=tail1->next;
        tail1->next=p1;
       
        tail1=tail1->next;
        
    }
    
    struct node*tail2,*p2;
    head2=(struct node*)malloc(sizeof(struct node));
    head2->next=NULL;
    tail2=head2;
    for(i=1;i<=n;i++)
    {
        p2=(struct node*)malloc(sizeof(struct node));
        p2->next=NULL;
        
        scanf("%d",&p2->data);
    
         p2->next=tail2->next;
        tail2->next=p2;
        tail2=tail2->next;
    }
    
    struct node*a,*b,*c;
    a=head1;
    b=head1->next;
    c=head2->next;
    free(head2);
    while(b&&c)
    {
        if(b->data>c->data)
        {
            a->next=c;
            a=c;
            c=c->next;
        }
        
        else
        {
            a->next=b;
            a=b;
            b=b->next;
        }
    }
    
    if(b)
        a->next=b;
    if(c)
        a->next=c;
    
    //遍历输出
    struct node*r;
    r=head1->next;
    while(r)
    {
        if(r->next==NULL)
           printf("%d",r->data);
        else printf("%d ",r->data);
        r=r->next;
    }
    return 0;
}

7-5 数据结构实验之链表五:单链表的拆分

输入N个整数顺序建立一个单链表,将该单链表拆分成两个子链表,第一个子链表存放了所有的偶数,第二个子链表存放了所有的奇数。两个子链表中数据的相对次序与原链表一致。

输入格式:
第一行输入整数N(1<=N<=100000)。

第二行依次输入N个整数。 (保证奇数偶数都存在)

输出格式:
第一行分别输出偶数链表与奇数链表的元素个数;

第二行依次输出偶数子链表的所有数据;

第三行依次输出奇数子链表的所有数据。

输入样例:
10
1 3 22 8 15 999 9 44 6 1001

输出样例:
4 6
22 8 44 6
1 3 15 999 9 1001

#include <stdio.h>
#include <stdlib.h>
int a1[1000000],a2[1000000000];
struct node
{
    int data;
    struct node *next;
};
int main()
{
    int n;
    scanf("%d",&n);
    int i=0;
    struct node*head,*tail;
    head=(struct node*)malloc(sizeof(struct node));
    head->next=NULL;
    tail=head;
    for(i=1;i<=n;i++)
    {
        struct node*p=(struct node*)malloc(sizeof(struct node));
        p->next=NULL;
        scanf("%d",&p->data);//存进去数据;
        //插入--顺序--尾插;
        p->next=tail->next;
        tail->next=p;
        tail=tail->next;
        
    }
    int cnt1=0,cnt2=0;
    struct node*r=head->next;
    while(r)
    {
        if(r->data%2==0)//偶数;
            a1[cnt1++]=r->data;
        else a2[cnt2++]=r->data;
        r=r->next;
    }
    printf("%d %d\n",cnt1,cnt2);
for(i=0;i<cnt1;i++)
    {
            if(i==0)
                printf("%d",a1[i]);
            else printf(" %d",a1[i]);
            
    }
        
        printf("\n");
         for(i=0;i<cnt2;i++)
             {
            if(i==0)printf("%d",a2[i]);
            else printf(" %d",a2[i]);
            
             }
         return 0;
}

7-6 数据结构实验之链表七:单链表中重复元素的删除

按照数据输入的相反顺序(逆位序)建立一个单链表,并将单链表中重复的元素删除(值相同的元素只保留最后输入的一个)。

输入格式:
第一行输入元素个数 n (1 <= n <= 15);

第二行输入 n 个整数,保证在 int 范围内。

输出格式:
第一行输出初始链表元素个数;

第二行输出按照逆位序所建立的初始链表;

第三行输出删除重复元素后的单链表元素个数;

第四行输出删除重复元素后的单链表。

输入样例:
10
21 30 14 55 32 63 11 30 55 30

输出样例:
10
30 55 30 11 63 32 55 14 30 21
7
30 55 11 63 32 14 21

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*next;
};
int main()
{
    int n;
    scanf("%d",&n);
    struct node*head=(struct node*)malloc(sizeof(struct node));
    head->next=NULL;
    int i=0;
    for(i=1;i<=n;i++)
    {
        struct node*p=(struct node*)malloc(sizeof(struct node));
        p->next=NULL;
        scanf("%d",&p->data);
        p->next=head->next;
        head->next=p;
    }//插入环节;
    printf("%d\n",n);
    struct node*r=head->next;
    while(r)
    {
        if(r->next==NULL)
            printf("%d",r->data);
        else printf("%d ",r->data);
        r=r->next;
    }
    struct node*q=head->next;
    while(q)
    {
        struct node*r=q->next;
        struct node*pre=q;
        while(r)
        {
            if(q->data==r->data)
            {
                pre->next=r->next;
                free(r);
                n--;
                r=pre->next;
            }
            else 
            {
                r=r->next;
                pre=pre->next;
            }
        }
        q=q->next;
    }
    printf("\n");
    printf("%d\n",n);
    
    struct node*z=head->next;
    while(z)
    {
        if(z->next==NULL)
            printf("%d",z->data);
        else printf("%d ",z->data);
        z=z->next;
    }
    
    return 0;
}

7-7 师–链表的结点插入

给出一个只有头指针的链表和 n 次操作,每次操作为在链表的第 m 个元素后面插入一个新元素x。若m 大于链表的元素总数则将x放在链表的最后。

输入格式:
多组输入。

每组数据首先输入一个整数n(1<=n<=100),代表有n次操作。

接下来的n行,每行有两个整数Mi(0<=Mi<=10000),Xi。

输出格式:
对于每组数据。从前到后输出链表的所有元素,两个元素之间用空格隔开。

输入样例:
4
1 1
1 2
0 3
100 4

输出样例:
3 1 2 4

Hint
样例中第一次操作1 1,由于此时链表中没有元素,1>0,所以此时将第一个数据插入到链表的最后,也就是头指针的后面。

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*next;
};
int main()
{
    int n,m,x,cnt=0,i=0;
    while(scanf("%d",&n)!=EOF)
    {
        cnt=0;
        struct node*head=(struct node*)malloc(sizeof(struct node));
        head->next=NULL;
       while(n--)
       {
           
           scanf("%d %d",&m,&x);
           struct node*p=(struct node*)malloc(sizeof(struct node));
           p->next=NULL;
           p->data=x;
           if(m>cnt)
           {
               m=cnt;
           }
           
           struct node*r=head;
           for(i=1;i<=m;i++)
           {
               r=r->next;
           }
           
           p->next=r->next;
           r->next=p;
           cnt++;
       }
        
        struct node*d=head->next;
        while(d)
        {
            if(d->next==NULL)
                printf("%d\n",d->data);
            else printf("%d ",d->data);
            d=d->next;
        }
    }
    
    return 0;
}

7-8 约瑟夫问题

n个人想玩残酷的死亡游戏,游戏规则如下:

n个人进行编号,分别从1到n,排成一个圈,顺时针从1开始数到m,数到m的人被杀,剩下的人继续游戏,活到最后的一个人是胜利者。

请输出最后一个人的编号。

输入格式:
输入n和m值。 (1<=n<=100 , 1<=m<=100)

输出格式:
输出胜利者的编号。

输入样例:
5 3

输出样例:
4

Hint
第一轮:3被杀

第二轮:1被杀

第三轮:5被杀

第四轮:2被杀

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int data;
    struct node*next;
};


int main()
{
    int n,m,i=0,cnt=0;
    scanf("%d %d",&n,&m);
    struct node*head=(struct node*)malloc(sizeof(struct node));
    head->next=NULL;
    struct node*tail=head;
    for(i=1;i<=n;i++)
    {
        struct node*p=(struct node*)malloc(sizeof(struct node));
        p->next=NULL;
        p->data=i;
        
        p->next=tail->next;
        tail->next=p;
        tail=tail->next;
    }
    
    tail->next=head->next;
    struct node*pre=head;
    struct node*r=head->next;
    while(r->next!=r)
    {
        cnt++;
        if(cnt%m==0)
        {
            pre->next=r->next;
            free(r);
            r=pre->next;
        }
        else
        {
            pre=pre->next;
            r=r->next;
        }
    }
    
    printf("%d",r->data);
    return 0;
}

7-9 数据结构实验之链表九:双向链表

学会了单向链表,我们又多了一种解决问题的能力,单链表利用一个指针就能在内存中找到下一个位置,这是一个不会轻易断裂的链。但单链表有一个弱点——不能回指。比如在链表中有两个节点A,B,他们的关系是B是A的后继,A指向了B,便能轻易经A找到B,但从B却不能找到A。一个简单的想法便能轻易解决这个问题——建立双向链表。在双向链表中,A有一个指针指向了节点B,同时,B又有一个指向A的指针。这样不仅能从链表头节点的位置遍历整个链表所有节点,也能从链表尾节点开始遍历所有节点。对于给定的一列数据,按照给定的顺序建立双向链表,按照关键字找到相应节点,输出此节点的前驱节点关键字及后继节点关键字。

输入格式:
第一行两个正整数n(代表节点个数),m(代表要找的关键字的个数)。第二行是n个数(n个数没有重复),利用这n个数建立双向链表。接下来有m个关键字,每个占一行。(1<=n<=50)

输出格式:
对给定的每个关键字,输出此关键字前驱节点关键字和后继节点关键字。如果给定的关键字没有前驱或者后继,则不输出。

注意:每个给定关键字的输出占一行。
一行输出的数据之间有一个空格,行首、行末无空格。

输入样例:
10 3
1 2 3 4 5 6 7 8 9 0
3
5
0

输出样例:
2 4
4 6
9

#include <stdio.h>
int a[100000];
int main()
{
    int n,m;
    scanf("%d %d",&n,&m);
    int i,j=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    
    int x;int pos=0;
    for(i=1;i<=m;i++)
    {
        scanf("%d",&x);
        for(j=1;j<=n;j++)
       {
        if(a[j]==x)
        {
            pos=j;
            break;
        }
    }
      if(pos==1)
          printf("%d\n",a[j+1]);
        else if(pos==n)
        printf("%d\n",a[j-1]);
        else printf("%d %d\n",a[j-1],a[j+1]);
  }
    
    
    return 0;
}

7-10 不敢死队问题

说到“敢死队”,大家不要以为我来介绍电影了,因为数据结构里真有这么道程序设计题目,原题如下:

有M个敢死队员要炸掉敌人的一个碉堡,谁都不想去,排长决定用轮回数数的办法来决定哪个战士去执行任务。如果前一个战士没完成任务,则要再派一个战士上去。现给每个战士编一个号,大家围坐成一圈,随便从某一个战士开始计数,当数到5时,对应的战士就去执行任务,且此战士不再参加下一轮计数。如果此战士没完成任务,再从下一个战士开始数数,被数到第5时,此战士接着去执行任务。以此类推,直到任务完成为止。

这题本来就叫“敢死队”。“谁都不想去”,就这一句我觉得这个问题也只能叫“不敢死队问题”。今天大家就要完成这道不敢死队问题。我们假设排长是1号,按照上面介绍,从一号开始数,数到5的那名战士去执行任务,那么排长是第几个去执行任务的?

输入格式:
输入包括多组数据,每行一个整数M(0<=M<=10000)(敢死队人数),若M=0,输入结束,不做处理。

输出格式:
输出一个整数n,代表排长是第n个去执行任务。

输入样例:
9
6
223
0

输出样例:
2
6
132

#include <stdio.h>
 #include <stdlib.h>
  #include <stdbool.h> 
  #include <string.h>

// 方便计算,将编号从0到(N-1)映射到1到N int a[16]; // 存储0~N-1 int n; // 有n个人围成一圈 int k; // k表示数到k后的人被踢出队列

// 模拟操作,对每个人返回其下一个被踢出队列的人 int next(int x) { // 获取x的下一个人 int i; for (i = 1; i <= k; i++) { x = (x + 1) % n; while (a[x] == -1) { // 跳过已经被从队列中剔除的人 x = (x + 1) % n; } } return x; }

int main() {
 while (scanf("%d", &n) != EOF && n != 0) 
 { memset(a, 0, sizeof(a)); 
 int s = 1; // 从编号为1的人开始数数 int i; k = 1; // 第一次踢出下标为1的人,从编号2开始计数

// 初始化数据
for (i = 0; i < n; i++) {
  a[i] = i;
}

int left = n;  // left表示剩余的人数
while (left > 1) {
  // 计算出下一个被踢出队列的人
  int x = next(s);
  a[x] = -1;  // 标记这个位置已经被踢出队列
  s = x;      // 开始数数的位置向后移动一位
  while (a[s] == -1) {  // 如果当前这个位置已经被踢出队列,就向后移动一位
    s = (s + 1) % n;
  }
  left--;
}

// 输出答案
for (i = 0; i < n; i++) {
  if (a[i] != -1) {
    printf("%d\n", a[i] + 1);
    break;
  }
}
} 

实验3 递推

7-1 养兔子

一对成熟的兔子每天能且只能产下一对小兔子,每次都生一公一母,每只小兔子的成熟期是1天,小兔子出生后隔一天才能再生小兔子。第一天某人领养了一对成熟的兔子,一公一母,请问第N天以后,他将会得到多少对兔子。

输入格式:
输入为一个整数n(1≤n≤90)。

输出格式:
对应输出第n天有几对兔子(假设没有兔子死亡现象,而且是一夫一妻制)。

输入样例1:
1

输出样例1:
1

输入样例2:
2

输出样例2:
2

#include<stdio.h>
int main()
{
    int n,i;
    long long int f[90];
    f[1]=1;
    f[2]=2;
    scanf("%d",&n);
    for(i=3;i<=n;i++)
    {
        f[i]=f[i-1]+f[i-2];
    }
    printf("%lld",f[n]);
    return 0;
}

7-2 母牛的故事

有一对夫妇买了一头母牛,它从第2年起每年年初生一头小母牛。每头小母牛从第四个年头开始,每年年初也生一头小母牛。
请编程实现在第n年的时候,共有多少头母牛?

输入格式:
输入为一个整数n(0< n< 55)

输出格式:
输出在第n年的时候母牛的数量。

输入样例1:
2

输出样例1:
2

输入样例2:
5

输出样例2:
6

#include<stdio.h>
int main()
{
    int f[55],i,n;
    f[1]=1;
    f[2]=2;
    f[3]=3;
    scanf("%d",&n);
    for(i=4;i<=n;i++)
    {
        f[i]=f[i-1]+f[i-3];
    }
    printf("%d\n",f[n]);
    return 0;
}

7-3 黄金时代

在古希腊时期,有一天毕达哥拉斯走在街上,在经过铁匠铺前他听到铁匠打铁的声音非常好听,于是驻足倾听。他发现铁匠打铁节奏很有规律,这个声音的比例被毕达哥拉斯用数学的方式表达出来。

这个比例就叫做黄金分割比,它是指将整体一分为二,较大部分与整体部分的比值等于较小部分与较大部分的比值,其比值约为0.6180339887。这个比例被公认为是最能引起美感的比例,因此被称为黄金分割。

现在小玉有一个正整数数列,这个数列的前一项和后一项的比值十分趋近于黄金分割比,即(a[i])/(a[i+1])~ 0.6180339887,(i>=1),可是她只知道数列的第一项是5,现在她想通过已有条件推断出数列的任意项,请你帮助她编写一个程序计算。(请留意题目提示)

输入格式:
每次输入一个整数n(1<=n<=20)

输出格式:
输出一个数,代表这个数列的第n项a[n]。

输入样例:
1

输出样例:
5

#include<stdio.h>
int main()
{
    int n,i;
    int a[20];
    scanf("%d",&n);
    a[1]=5;
    a[2]=8;
    for(i=3;i<=n;i++)
    {
        a[i]=a[i-1]+a[i-2];
    }
    printf("%d",a[n]);
    return 0;
}

7-4 骨牌铺方格

在2×n的一个长方形方格中,用一个1× 2的骨牌铺满方格,输入n ,输出铺放方案的总数.
例如n=3时,为2× 3方格,骨牌的铺放方案有三种,如下图:

输入格式:
输入包含一个整数n,表示该测试实例的长方形方格的规格是2×n (0< n<=50)。

输出格式:
输出铺放方案的总数。

输入样例:
在这里给出一组输入。例如:

3

输出样例:
在这里给出相应的输出。例如:

3

#include<stdio.h>
int main()
{
    long long int a[50];
    int i,n;
    a[1]=1;
    a[2]=2;
    scanf("%d",&n);
    for(i=3;i<=n;i++)
    {
        a[i]=a[i-1]+a[i-2];
    }
    printf("%lld",a[n]);
}

7-5 马拦过河卒

棋盘上A点有一个过河卒,需要走到目标B点。卒行走的规则:可以向下、或者向右。同时在棋盘上C点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制点。因此称之为“马拦过河卒”。
棋盘用坐标表示,A点(0,0)、B点(n,m)(n,m为不超过15的整数),同样马的位置坐标是需要给出的。现在要求你计算出卒从A点能够到达B点的路径的条数,假设马的位置是固定不动的,并不是卒走一步马走一步。

输入格式:
一行四个数据,用空格分隔,分别表示B点的坐标和马的坐标。

输出格式:
一个数据,表示所有的路径条数。

输入样例:
6 6 3 3

输出样例:
6

#include<stdio.h>
int main()
{
    int j,i,n,m,x,y;
    int f[20][20],g[20][20];
    scanf("%d %d %d %d",&n,&m,&x,&y);
    for(i=0;i<=n;i++)
    {
        for(j=0;j<=m;j++)
        {
            f[i][j]=0;//每一点的路径都初始化为0;
        }
    }
    for(i=0;i<=n;i++)
    {
        for(j=0;j<=m;j++)
        {
            g[i][j]=0;//先初始化每一个点都为不是🐎的控制点
        }
    }
    g[x][y]=1;
    g[x-1][y-2]=1;
    g[x+1][y-2]=1;
    g[x-2][y-1]=1;
    g[x+2][y-1]=1;
    g[x-2][y+1]=1;
    g[x+2][y+1]=1;
    g[x-1][y+2]=1;
    g[x+1][y+2]=1;//然后根据🐎的“日”字走向,找到🐎的控制点,🐎的控制点我们就用1来表示
    for(i=0;i<=n;i++)//先分析列
    {
        if(g[i][0]!=1)//如果这一列都不是🐎的控制点,那路径就是一条
            f[i][0]=1;
        else for(;i<=n;i++)//从该i开始,往后的直接就是0了,不用往下看了
            f[i][0]=0;
    }
    for(j=0;j<=m;j++)
    {
        if(g[0][j]!=1)
            f[0][j]=1;
        else for(;j<=m;j++)
            f[0][j]=0;
    }
    for(i=1;i<=n;i++)
    {
        for(j=1;j<=m;j++)
        {
            if(g[i][j]==0)
            {
                f[i][j]=f[i-1][j]+f[i][j-1];//如果不是🐎的控制点,那就是把从左和从上的两个加起来,就是它的路径数
            }
        }
    }
    printf("%d",f[n][m]);
    return 0;
}

7-6 爬楼梯

小明是个非常无聊的人,他每天都会思考一些奇怪的问题,比如爬楼梯的时候,他就会想,如果每次可以上一级台阶或者两级台阶,那么上 n 级台阶一共有多少种方案?

输入格式:
输入只有一行为一个正整数 n(1 ≤ n ≤ 50)。

输出格式:
输出符合条件的方案数。

输入样例:
在这里给出一组输入。例如:

4

输出样例:
5

#include<stdio.h>
int main()
{
    int n,i;
    long long int a[50];
    a[1]=1;
    a[2]=2;
    scanf("%d",&n);
    for(i=3;i<=n;i++)
    {
        a[i]=a[i-1]+a[i-2];
    }
    printf("%lld",a[n]);
    return 0;
}

7-7 三国佚事——巴蜀之危

话说天下大势,分久必合,合久必分。。。却道那魏蜀吴三国鼎力之时,多少英雄豪杰以热血谱写那千古之绝唱。古人诚不我欺,确是应了那句“一将功成万骨枯”。
是夜,明月高悬。诸葛丞相轻摇羽扇,一脸愁苦。原来是日前蜀国战事吃紧,丞相彻夜未眠,奋笔急书,于每个烽火台写下安排书信。可想,这战事多变,丞相运筹 帷幄,给诸多烽火台定下不同计策,却也实属不易。
谁成想这送信小厮竟投靠曹操,给诸葛丞相暗中使坏。这小厮将每封书信都投错了烽火台,居然没有一封是对的。不多时小厮便被抓住,前后之事却也明朗。这可急坏了诸葛丞相,这书信传错,势必会让蜀军自乱阵脚,不攻自破啊!
诸葛丞相现在想知道被这小厮一乱,这书信传错共有多少种情况。

输入格式:
输入一个正数n,代表丞相共写了n(1 <= n <= 20)封书信。

输出格式:
输出书信传错的情况数。

输入样例:
3

输出样例:
2

#include<stdio.h>
int main()
{
    int n,i;
    scanf("%d",&n);
    long long int a[20];
    a[1]=0;
    a[2]=1;
    for(i=3;i<=n;i++)
    {
        a[i]=(i-1)*(a[i-2]+a[i-1]);
    }
    printf("%lld",a[n]);
    return 0;
}

7-8 王小二切饼

王小二自夸刀工不错,有人放一张大的煎饼在砧板上,问他:“饼不许离开砧板,切n(1<=n<=100)刀最多能分成多少块?”

输入格式:
输入切的刀数n。

输出格式:
输出为切n刀最多切的饼的块数。

输入样例:
100

输出样例:
5051

#include<stdio.h>
int main()
{
    int n,i;
    long long int a[100];
    scanf("%d",&n);
    a[1]=2;
    for(i=2;i<=n;i++)
    {
        a[i]=a[i-1]+i;
    }
    printf("%lld",a[n]);
    return 0;
}

7-9 蟠桃记

孙悟空在大闹蟠桃园的时候,第一天吃掉了所有桃子总数一半多一个,第二天又将剩下的桃子吃掉一半多一个,以后每天吃掉前一天剩下的一半多一个,到第n天准备吃的时候只剩下一个桃子。这下可把神仙们心疼坏了。
请帮忙计算一下,第一天开始吃的时候一共有多少个桃子?

输入格式:
输入包含一个正整数n(1≤n≤30),表示只剩下一个桃子的时候是在第n天发生的。

输出格式:
输出第一天开始吃的时候桃子的总数。

输入样例:
2

输出样例:
4

#include<stdio.h>
int main()
{
    int n,i,m,sum=0;
    long long int a[30];
    a[1]=1;
    scanf("%d",&n);
    for(i=2;i<=n;i++)
    {
        a[i]=(a[i-1]+1)*2;
    }
    printf("%lld",a[n]);
    return 0;
}

7-10 C语言实验——拍皮


小瑜3岁了,很喜欢玩皮球,看来今后喜欢打篮球的_。最近她发现球从手中落下时,每次落地后反跳回原高度的一半,再落下,每次球落地时数球跳了几次,数到n次时爸爸在边上喊停,问小瑜现在球到底总共走了多少距离,小瑜故作沉思状,爸爸又问接下来小球能跳多高啊,小瑜摇摇头,心想还没跳我怎么知道啊,难道爸爸是神啊!这时的你在边上出主意想给小瑜写个程序计算一下,因此任务就交给你啦!
假设球的初始高度为h,计算第n次落地时球经过的距离,以及落地后反弹能有多高。

输入格式:
每行有两个数,球的初始高度h(h<=100)和球落地的次数n(n <= 10),用空格分隔。

输出格式:
输出第n次反弹时球经过的距离和球最后的高度,保留小数点后2位。

输入样例:
100 1

输出样例:
100.00 50.00

#include<stdio.h>
int main()
{
    int i,m,j;
    double n;
    double a[10],b[10];
    scanf("%lf %d",&n,&m);
    a[0]=n;
    b[0]=0;
    b[1]=n;
    for(i=1;i<=m;i++)
    {
        a[i]=a[i-1]/2.0;
    }
    for(j=2;j<=m;j++)
    {
        b[j]=b[j-1]+a[j-1]*2.0;
    }
    printf("%.2f %.2f\n",b[m],a[m]);
    return 0;
}

实验4 递归

函数题:

6-1 数据结构实验之排序八:快速排序

本题要求实现一个快速排序函数。
给定 N ( N<= 100000 ) 个 int 范围内的整数,要求用快速排序对数据进行升序排列。

函数接口定义:
void Quick_sort (int array[], int l, int r);
AI助手
其中 array[] 、 l 、r 都是用户传入的参数。 array[] 是需要排序的数组,数组长度不会超过100000; l 和 r 是需要进行排序的左端点和右端点。

裁判测试程序样例:
#include <stdio.h>

void Quick_sort (int array[], int l, int r);

int main()
{

int N, array[100000];
scanf(“%d”, &N);
for(int i=0; i<N; i++)
{
scanf(“%d”, &array[i]);
}

Quick_sort(array, 0, N-1);

for(int i=0; i<N; i++)
{
printf(“%d “, array[i]);
}
printf(”\n”);
return 0;
}

/* 请在这里填写答案 */

输入样例:
8
49 38 65 97 76 13 27 49
输出样例:
在这里给出相应的输出。例如:

13 27 38 49 49 65 76 97

void Quick_sort (int array[],int l,int r)
{
    int x=array[l],i=l,j=r;
    if(l>=r)
        return ;
    while(i<j)
    {
        while(i<j&&array[j]>=x)
        {
        j--;
        }
        array[i]=array[j];
        while(i<j&&array[i]<=x)
        {
        i++;
        }
        array[j]=array[i];
    }
    array[i]=x;
    Quick_sort(array,l,i-1);
    Quick_sort(array,i+1,r);
}

6-2 二分查找

本题要求实现一个二分查找函数。

给出含有 n 个数的升序序列,保证序列中的数两两不相等,这n个数编号从1 到n。

然后给出 q 次询问,每次询问给出一个数x,若x存在于此序列中,则输出其编号,否则输出-1。

函数接口定义:
int Binary_search(int array[], int l, int r, int x);

其中 array 、 l 、 r 、 x都是用户传入的参数。 array 是要进行查询的序列,保证序列有序且出现的数字均不重复; l 和 r 是二分查找的区间的左端点和右端点;x 代表要在序列中查询的值。

当在序列中查询到 x 时,函数返回 x 在序列中出现的位置编号;否则函数返回 -1。

裁判测试程序样例:
#include <stdio.h>

int Binary_search(int array[], int l, int r, int x);

int main()
{
int N, Q, i, x, ans;
int array[100005];

scanf("%d",&N);
    
for(i=1; i<=N; i++)
{
    scanf("%d", &a[i]);
}
    
scanf("%d",&Q);
    
while(Q--)
{
    scanf("%d", &x);
    ans = Binary_search(a, 1, N, x);
    printf("%d\n", ans);
}
    
return 0;

}

/* 请在这里填写答案 */

输入样例:
5
1 3 5 7 9
3
1
5
8

输出样例:
1
3
-1

int Binary_search(int array[],int l,int r,int x)
{
    while(l<=r)
    {
        int mid=(l+r)/2;
        if(array[mid]==x)
            return mid;
        else if(array[mid]>x)
            r=mid-1;
        else if(array[mid]<x)
            l=mid+1;
    }
    return -1;
}

编程题目:

7-1 计算组合数

计算组合数。C(n,m),表示从n个数中选择m个的组合数。

计算公式如下:

若:m=0,C(n,m)=1

否则, 若 n=1,C(n,m)=1

  否则,若m=n,C(n,m)=1

        否则 C(n,m) = C(n-1,m-1) + C(n-1,m)

输入格式:
第一行是正整数N (1 <= N<= 100),表示有N组要求的组合数。

接下来N行,每行两个整数n,m (0 <= m <= n <= 20)。

输出格式:
输出N行。每行输出一个整数表示C(n,m)。

输入样例:
在这里给出一组输入。例如:

3
2 1
3 2
4 0
输出样例:
在这里给出相应的输出。例如:

2
3
1

#include <stdio.h>
int fun(int n,int m)
{
    if(m==0||n==1||n==m) return 1;
    else return fun(n-1,m-1)+fun(n-1,m);
}
int main()
{
    int N;
    scanf("%d",&N);
    while(N--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        printf("%d\n",fun(n,m));
    }

    return 0;
}

7-2 神奇的函数

神奇的函数是这样被定义的:

F(n, m) = {
if(n == 1 || m == 1)
F(n, m) = 1;
else
F(n, m) = F(n-1, m) + F(n, m-1);
}
输入格式:
第一行是正整数N (1 <= N<= 30),表示有N组数据。

接下来N行,每行两个整数n,m (1 <= n, m <= 10)。

输出格式:
输出N行。每行输出一个整数表示F(n,m)。

输入样例:
在这里给出一组输入。例如:

1
1 2
输出样例:
在这里给出相应的输出。例如:

1


#include <stdio.h>
int fun(int n,int m)
{
    if(n==1||m==1) return 1;
    else return fun(n-1,m)+fun(n,m-1);
}
int main()
{
    int a;
    scanf("%d",&a);
    int n,m;
    while(a--)
    {
        scanf("%d %d",&n,&m);
        printf("%d\n",fun(n,m));
    }
    
    return 0;
}

7-3 汉诺塔

汉诺塔(又称河内塔)问题是印度的一个古老的传说。

开天辟地的神勃拉玛在一个庙里留下了三根金刚石的棒A、B和C,A上面套着n个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从A棒搬到C棒上,规定可利用中间的一根B棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。

僧侣们搬得汗流满面,可惜当n很大时这辈子恐怕就很搬完了。

聪明的你还有计算机帮你完成,你能写一个程序帮助僧侣们完成这辈子的夙愿吗?

输入格式:
输入金片的个数n (1 <= n <= 10)。

输出格式:
输出搬动金片的全过程。格式见样例。

输入样例:
在这里给出一组输入。例如:

2
输出样例:
在这里给出相应的输出。例如:

Move disk 1 from A to B
Move disk 2 from A to C
Move disk 1 from B to C

#include <stdio.h>
void m(int n,char a,char b,char c)
{
    if(n==1) printf("Move disk %d from %c to %c\n",n,a,c);
    else 
    {
        m(n-1,a,c,b);
        printf("Move disk %d from %c to %c\n",n,a,c);
        m(n-1,b,a,c);
    }
}
int  main()
{
    int n;
    scanf("%d",&n);
    m(n,'A','B','C');
    return 0;
}

7-4 全排列问题

从n个不同元素任取m(m<=n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列,当m=n时所有的排列情况叫全排列。现输入n个递增的数,请你输出这n个数的全排列。全排列输出顺序如样例所示。

输入格式:
第一行先输入一个整数n(1<=n<=10)。

接下来是一行输入n个由空格分开的互不相同的整数num (1 <= num <= 90000)。

输出格式:
对于每组数据,每一种排列占一行,各元素间用逗号隔开。

输入样例:
在这里给出一组输入。例如:

3
1 2 3
输出样例:
在这里给出相应的输出。例如:

1,2,3
1,3,2
2,1,3
2,3,1
3,1,2
3,2,1

#include<stdio.h>

int q[15];
int f[15];//当前数是否用过
int n;
int ans[15];//存每一个遍历的结果
void dfs(int u)//当前填的是第几个位置
{
    if(u == n + 1)
    {
        for(int i = 1; i <= n; i++)
        {
            if(i == 1)
            {
                printf("%d", ans[i]);
            }
            else printf(",%d", ans[i]);
        }
        printf("\n");
    }
    
    for(int i = 1; i <= n; i++)
    {
        if(f[i] == 0)
        {
            f[i] = 1;//这个下标对应的数用过了
            ans[u] = q[i];
            dfs(u + 1);
//             ans[u] = 0;
            f[i] = 0; 
        }
    }
}
int main()
{
    scanf("%d", &n);
    
    for(int i = 1; i <= n; i++)
    {
        scanf("%d", &q[i]);
    }
    
    dfs(1);
    return 0;
}

7-5 喵帕斯之天才算数少女

莲酱要上一年级了,但是老师给他出了一个特别难的算术题。

4123.png

老师给出了一个函数

F(m, n)的定义是:

若m=0,返回n+1。

若m>0且n=0,返回F(m-1,1)。

若m>0且n>0,返回F(m-1,F(m,n-1))。

给出 m 和 n,计算 F(m, n) 的值。

输入格式:
第一行输入一个整数 t, 代表有 t 组数据。(1 <= t <= 15)

每组数据输入一行,包含两个非负整数 m,n。(0 <= m <= 3, 0 <= n <= 10)

输出格式:
每组数据输出一行,为 F(m, n) 的答案

输入样例:
在这里给出一组输入。例如:

3
3 2
3 10
2 1
输出样例:
在这里给出相应的输出。例如:

29
8189
5

#include <stdio.h>
int fun(int m,int n)
{
    if(m==0) return n+1;
    else if(m>0&&n==0) return fun(m-1,1);
    else if(m>0&&n>0) return fun(m-1,fun(m,n-1));
}
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int m,n;
        scanf("%d %d",&m,&n);
        printf("%d\n",fun(m,n));
    }
    
    return 0;
}

7-6 青蛙过河

1)一条小溪尺寸不大,青蛙可以从左岸跳到右岸,在左岸有一石柱L,石柱L面积只容得下一只青蛙落脚,同样右岸也有一石柱R,石柱R面积也只容得下一只青蛙落脚。

2)有一队青蛙从小到大编号:1,2,…,n。

3)初始时:青蛙只能趴在左岸的石头 L 上,按编号一个落一个,小的落在大的上面-----不允许大的在小的上面。

4)在小溪中有S个石柱、有y片荷叶。

5)规定:溪中的每个石柱上如果有多只青蛙也是大在下、小在上,每个荷叶只允许一只青蛙落脚。

6)对于右岸的石柱R,与左岸的石柱L一样允许多个青蛙落脚,但须一个落一个,小的在上,大的在下。

7)当青蛙从左岸的L上跳走后就不允许再跳回来;同样,从左岸L上跳至右岸R,或从溪中荷叶、溪中石柱跳至右岸R上的青蛙也不允许再离开。

问题:在已知小溪中有 s 根石柱和 y 片荷叶的情况下,最多能跳过多少只青蛙?

输入格式:
第一行输入一个整数 t, 代表有 t 组数据。(1 <= t <= 15)

每组占一行,每行包含2个数s(s是小溪中的石柱数目)、y(y是小溪中的荷叶数目)。(0 <= s <= 10 , 0 <= y <= 10)

输出格式:
对每组输入,输出有一行,输出最多能跳过的青蛙数目。

输入样例:
在这里给出一组输入。例如:

2
0 2
1 2
输出样例:
在这里给出相应的输出。例如:

3
6

#include <stdio.h>
#include <math.h>
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n,m;
        scanf("%d %d",&n,&m);
        m+=1;
         printf("%.0f\n",m*pow(2,n));
    }
    return 0;
}

7-7 第k小的数

现有一个包含n个整数(1<=n<=900000)的无序序列(保证序列内元素各不相同),输入一个整数k(1<=k<=n),请用较快的方式找出该序列的第k小数并输出。

输入格式:
第一行先输入两个整数,n和k。

接下来是一行输入n个由空格分开的互不相同的整数num(1<=num<=90000000)。

输出格式:
输出该组数据中第k小的数num。

输入样例:
6 4
3 2 5 1 4 6
输出样例:
4

#include <stdio.h>
int a[1000000];
void m(int a[],int l,int r)
{
    int i=l;int j=r;
    if(l>=r) return ;
    int x=a[l];
    while(i<j)
    {
        while(i<j&&a[j]>=x)
        j--;
         a[i]=a[j];
        while(i<j&&a[i]<=x)
        i++;
          a[j]=a[i];
    }
    a[i]=x;
    m(a,l,i-1);
    m(a,i+1,r);
}
int main()
{
    int n,k;
    scanf("%d %d",&n,&k);
    int i=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
   m(a,1,n);
    printf("%d\n",a[k]);
    return 0;
    
}

7-8 第X大的数

X最近爱上了区间查询问题,给出N (N <= 100000) 个数,然后进行M (M <= 50) 次询问,每次询问时,输入一个数X (1 <= X <= N),输出N个数中第X大的数。

输入格式:
首先输入一个整数N,代表有N个数,下面一行包含N个整数,用空格隔开。然后为一个整数M,代表有M次询问,下面的M行,每行一个整数X。

输出格式:
输出N个数中第X大的数。

输入样例:
4
1 2 2 3
4
1
2
3
4
输出样例:
在这里给出相应的输出。例如:

3
2
2
1

#include <stdio.h>
int a[1000000000];
      void m(int a[],int l,int r)
{
    if(l>=r) return ;
    int i=l,j=r;
    int x=a[l];
    while(i<j)
    {
        while(a[j]<=x&&i<j)
            j--;
        a[i]=a[j];
        while(a[i]>=x&&i<j)
            i++;
        a[j]=a[i];
    }
    
    a[i]=x;
    m(a,l,i-1);
    m(a,i+1,r);
    
}

int main()
{
    int n;
    scanf("%d",&n);
    int i=0;
    for(i=1;i<=n;i++)
    {
        scanf("%d",&a[i]);
    }
    m(a,1,n);
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int x;
        scanf("%d",&x);
        printf("%d\n",a[x]);
    }
    return 0;
}

实验5 贪心

7-1 活动选择

学校的大学生艺术中心周日将面向全校各个学院的学生社团开放,但活动中心同时只能供一个社团活动使用,并且每一个社团活动开始后都不能中断。现在各个社团都提交了他们使用该中心的活动计划(即活动的开始时刻和截止时刻)。请设计一个算法来找到一个最佳的分配序列,以能够在大学生艺术中心安排不冲突的尽可能多的社团活动。
比如有5个活动,开始与截止时刻分别为:

在这里插入图片描述

最佳安排序列为:1,4,5。

输入格式:
第一行输入活动数目n(0<n<100);
以后输入n行,分别输入序号为1到n的活动使用中心的开始时刻a与截止时刻b(a,b为整数且0<=a<b<24,a,b输入以空格分隔)。

输出格式:
输出最佳安排序列所包含的各个活动(按照活动被安排的次序,两个活动之间用逗号分隔),如果有多个活动安排序列符合要求输出字典序最小的序列。

输入样例:
6
8 10
9 16
11 16
14 15
10 14
7 11

输出样例:
1,5,4

#include<stdio.h>
struct
{
    int begin,end,num;
}a[100],t;
int main()
{
    int n,i,j;
    scanf("%d",&n);
    for(i=0;i<n;i++)
    {
        scanf("%d %d",&a[i].begin,&a[i].end);
        a[i].num=i+1;
    }
    for(i=0;i<n-1;i++)
    {
        for(j=0;j<n-i-1;j++)
        {
            if(a[j].end>a[j+1].end)
            {
                t=a[j+1];
                a[j+1]=a[j];
                a[j]=t;
            }
        }
    }
    int now=a[0].end;
    printf("%d",a[0].num);
    for(i=1;i<n;i++)
    {
        if(a[i].begin>=now)
        {
                printf(",%d",a[i].num);
            now=a[i].end;
        }
    }
    printf("\n");
    return 0;
}

7-2 删数问题

键盘输入一个高精度的正整数n(≤100位),去掉其中任意s个数字后剩下的数字按照原来的左右次序组成一个新的正整数。
编程对给定的n与s,寻找一种方案,使得剩下的数字组成的新数最小。

输入格式:
输入两个数字,分别为原始数n,要去掉的数字数s (s < n);

输出格式:
输出去掉s个数后最小的数。

输入样例:
178543 4

输出样例:
13

#include<stdio.h>
#include<string.h>       
char n[250];        //利用字符数组来储存高精度数
int s,i,len,flag=1;
int main()
{
    scanf("%s %d",n,&s);
    len=strlen(n);             //这里是长度函数,取n的长度并赋值给len
    while(s!=0)              //只要s不是0,取数的工作就没有做完!
    {
        i=0;
        while(n[i]<=n[i+1]) //括号内的条件保证了不降序的条件,当它退出时,就是升序数列的末尾了
            i++;
        while(i<len-1)         //这时已经找到了要取出的数——n[i],这是取出的过程
        {n[i]=n[i+1];i++;}         
        len--;                //取出后数字长度减1
        s--;                   //消耗掉一次取出次数
    }
    for(i=0;i<len;i++)         //输出时要小心最高位是0的问题!处理输出……
    {
        if(n[i]=='0'&&i<len-1&&flag==1)  //如果即将输出的这一位是0且是最高位而且不是最后一个
            continue;           //跳过
        else
        {printf("%c",n[i]);flag=0;}//输出并且明确n[i]不再是最高位
    }
    return 0;
}

7-3 活动选择问题

sdut 大学生艺术中心每天都有n个活动申请举办,但是为了举办更多的活动,必须要放弃一些活动,求出每天最多能举办多少活动。

输入格式:
输入第一行为申请的活动数n(n<100),从第2行到n+1行,每行两个数,是每个活动的开始时间b,结束时间e;

输出格式:
输出每天最多能举办的活动数。

输入样例:
12
15 20
15 19
8 18
10 15
4 14
6 12
5 10
2 9
3 8
0 7
3 4
1 3

输出样例:
5

#include <stdio.h>
struct node
{
    int begin, end;
} q[105], t;
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < n; i++)
        scanf("%d %d", &q[i].begin, &q[i].end);
    for (int i = 0; i < n - 1; i++)
        for (int j = 0; j < n - 1 - i; j++)
        {
            if (q[j].end > q[j + 1].end)
            {
                t = q[j];
                q[j] = q[j + 1];
                q[j + 1] = t;
            }
        }
    int ans = 0, pos = 0;
    for (int i = 0; i < n; i++)
    {
        if (q[i].begin >= pos)
        {
            ans++;
            pos = q[i].end;
        }
    }
    printf("%d\n", ans);
    return 0;
}

7-4 区间覆盖问题

用i来表示x坐标轴上坐标为[i-1,i]的长度为1的区间,并给出n个不同的整数,表示n个这样的区间。

现在要求画m条线段覆盖住所有的区间,

条件是:每条线段可以任意长,但是要求所画线段的长度之和最小,

并且线段的数目不超过m。

输入格式:
输入包括多组数据,每组数据的第一行表示区间个数n(1≤n≤200) 和所需线段数m(1≤m≤50),第二行表示n个点的坐标i(1≤i≤200)。

输出格式:
每组输出占一行,输出m条线段的最小长度和。

输入样例:
5 3
1 3 8 5 11

输出样例:
7

#include <stdio.h>
int i,j,m,n,t,sum,a[250],b[250];
int main()
{
 
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(i=0;i<n;i++){
        scanf("%d",&a[i]);
        }
        for(i=0;i<n-1;i++)
            for(j=0;j<n-i-1;j++)
            {
                if(a[j]>a[j+1]){
                    t=a[j];
                    a[j]=a[j+1];
                    a[j+1]=t; 
                }
                    
            }
        sum=a[n-1]-a[0]+1;
        for(i=0;i<n-1;i++)
        {
            b[i]=a[i+1]-a[i]-1;
        }
        for(i=0;i<n-1;i++)
            for(j=0;j<n-i-1;j++)
            {
                if(b[j]<b[j+1]){
                    t=b[j];
                    b[j]=b[j+1];
                    b[j+1]=t; 
                }
                    
            }
        for(i=0;i<m-1;i++)
        {
sum-=b[i];
        }
        printf("%d\n",sum);
    }
}

7-5 最少拦截系统

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但
以后每一发炮弹都不能超过前一发的高度.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹.
怎么办呢?多搞几套系统呗!你说说倒蛮容易,成本呢?成本是个大问题啊.所以俺就到这里来求救了,请帮助计算一下最少需要多少套拦截系统.

输入格式:
输入包括:导弹总个数(正整数),导弹依此飞来的高度(雷达给出的高度数据是不大于30000的正整数,用空格分隔)

输出格式:
对应输出拦截所有导弹最少要配备多少套这种导弹拦截系统.

输入样例:
8 389 207 155 300 299 170 158 65

输出样例:
2

#include <stdio.h>
#include <string.h>
int main()
{
    int n;
    int a[201], x;
    scanf("%d", &n);
    memset(a, -1, sizeof(a));
    int m = 0;
    while (n--)
    {
        scanf("%d", &x);
        int i;
        for (i = 0; i < m; i++)
        {
            if (x <= a[i])
            {
                a[i] = x;
                break;
            }
        }
        if (i == m)
            a[m++] = x;
    }
    printf("%d\n", m);
    return 0;
}

7-6 悼念512汶川大地震遇难同胞

时间:2008年5月16日(震后第4天)
地点:汶川县牛脑寨
人物:羌族老奶奶

【转载整理】牛脑寨是一个全村600多人的羌族寨子,震后几天,这里依然能常常听到隆隆的声音,那是对面山上石头不断滑落的声音。在完成整个突击队的抢修移动基站的任务后,我提着相机开始记录这里的受创情况。
突然,我的视线里出现一个羌族老人,这让我无比的震惊,要知道,那是一个极陡的坡,这个佝偻着腰的老人是怎么艰难地爬上来的?她上来做什么?

老人背后是极陡的坡,她只有一只眼睛有依稀的视力,望着满地废墟,她徘徊了很久。家在哪里,她极力地用很低的视力找寻着。她曾经的家就在旁边,但是满目废墟已经让老人看不出来。她举目远眺,期望那里能看到家的一点点痕迹。原来家就在旁边,左手抓住一个房橼,努力让自己站住,地震过去三天了,她第一次回到曾经的家。

一个倒塌的柜子,里面装着一丝希望,老人很吃力地搬动掩盖在柜子上的薪柴。老人找到一把木匠用的刨子,老泪纵横,或许有哪个逝去的亲人是木匠。睹物思人,逝者已矣。

继续找,一把散碎的挂面出现在我的眼前。她颤颤巍巍地捞起铺满灰尘的挂面,再次流出了眼泪…
看着她仔细地把挂面放进胸前的围腰里,我顿然感觉到,这是老人在得到外援之前赖以生存的口粮了,如果不是交通中断,外部救援进不来,老人家又何必拖着80多岁的躯体,强忍失去亲人的痛苦,重新回到这夺取她亲人生命的废墟,寻找这点点挂面?老人是真饿了…

老人佝偻着腰,低声喃喃地念着那两句话“你们走了,我可怎么活”,拿着那对我们身处城市的人们微不足道的挂面,远去了…

PS: 拍完这组照片后我才知道,5月14号军用运输飞机第一次给汶川空投救援物资就掉在牛脑寨,受灾的村民们没有占为己有,而是汗流浃背地走了两个小时背到山下的县城交给政府。

对于幸存的灾民来说,最急待解决的显然是温饱问题,救灾部队一边在组织人员全力打通交通,一边在组织采购粮食。现在假设下拨了一定数量的救灾经费要去市场采购大米(散装)。如果市场有m种大米,各种大米的单价和重量已知,请问,为了满足更多灾民的需求,最多能采购多少重量的大米呢?

输入格式:
第一行是两个整数n和m(0 < n <= 1000, 0 < m <= 1000 ),分别表示经费的金额和大米的种类,然后是m行数据,每行包含2个整数p和h(1 <= p <= 25,1 <= h <= 100),分别表示单价和对应大米的重量。

输出格式:
请输出能够购买大米的最多重量(你可以假设经费买不光所有的大米)。输出占一行,保留2位小数。

输入样例:
7 2
3 3
4 4

输出样例:
2.33

#include <stdio.h>
struct
{
 int p,h;
}a[1000],t;
int main()
{
        int i,j,n,m;
        double ans=0;
        scanf("%d%d",&n,&m);
        for(i=0;i<m;i++)
        {
            scanf("%d%d",&a[i].p,&a[i].h);
        }
        for(i=0;i<m;i++)
        {
            for(j=0;j<m-i-1;j++)
            {
                if(a[j].p>a[j+1].p)
                {
                    t=a[j];
                    a[j]=a[j+1];
                    a[j+1]=t;
                }
            }
        }
        for(i=0;i<m;i++)
        {
            if(a[i].h*a[i].p>n)
            {
                break;
            }
            ans+=a[i].h*1.0;
            n-=a[i].h*a[i].p;
        }
        ans=ans+n*1.0/a[i].p;
        printf("%.2f\n",ans);
    return 0;
}

7-7 懒虫小鑫

小鑫是个大懒虫,但是这一天妈妈要小鑫去山上搬些矿石去城里卖以补贴家用。小鑫十分的不开心。不开心归不开心,小鑫还是要做这件事情的。

我们把这个事情简化一下。有n块矿石,设第i块矿石由两个数字wi和pi表示。分别表示这块石头的重量和可以卖的价钱。小鑫每次只能搬一块矿石去城里卖,所以他决定每次都会搬重量最小的那块。如果恰好有几块重量相等,那就在这几块中挑选价值最高的带走。

由于路程原因。小鑫每天只能打m个来回,也就意味着他只能卖掉m块矿石。你能计算出他能得到多少钱么?

输入格式:
第一行为n,m。m≤n≤10000。

接下来有n行,每行两个数代表石头的w与p。

输出格式:
对于每组数据,输出有一行为一个数,为答案。

输入样例:
4 2
1 2
1 3
2 2
3 4

输出样例:
5

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct node
{
    int p, h;
} a[10001], t;
 
void sort(int l, int r) //快排
{
    t = a[l];
    int i = l, j = r;
    if (l >= r)
        return;
    while (i < j)
    {
        while ((a[j].h > t.h || (a[j].h == t.h && a[j].p <= t.p)) && i < j)
            j--;
        a[i] = a[j];
        while ((a[i].h < t.h || (a[i].h == t.h && a[i].p >= t.p)) && i < j)
            i++;
        a[j] = a[i];
    }
    a[i] = t;
    sort(l, i - 1);
    sort(i + 1, r);
}
 
int main()
{
    int n, m;
    while (~scanf("%d %d", &n, &m))
    {
        for (int i = 0; i < n; i++)
        {
            scanf("%d %d", &a[i].h, &a[i].p);
        }
        sort(0, n - 1);
        int ans = 0;
        for (int i = 0; i < m; i++)
            ans += a[i].p;
        printf("%d\n", ans);
    }
    return 0;
}

7-8 装船问题

王小二毕业后从事船运规划工作,吉祥号货轮的最大载重量为M吨,有10种货物可以装船。第i种货物有wi吨,总价值是pi。王小二的任务是从10种货物中挑选若干吨上船,在满足货物总重量小于等于M的前提下,运走的货物的价重比最大。

输入格式:
输入数据的第一行有一个正整数M(0 < M < 10000),表示所有货物最大载重量。在接下来的10行中,每行有若干个数(中间用空格分开),第i行表示的是第i种货物的货物的总价值pi ,总重量wi。(pi是wi的整数倍,0 < pi , wi < 1000)

输出格式:
输出一个整数,表示可以得到的最大价值。

输入样例:
在这里给出一组输入。例如:

100
10 10
20 10
30 10
40 10
50 10
60 10
70 10
80 10
90 10
100 10

输出样例:
在这里给出相应的输出。例如:

550

#include <stdio.h>
struct node
{
    int wi, pi, b;
} q[10010], t;
void sort(int l, int r)
{
    if (l >= r)
        return;
    t = q[l];
    int i = l, j = r;
    while (i < j)
    {
        while (q[j].b <= t.b && i < j)
            j--;
        q[i] = q[j];
        while (q[i].b >= t.b && i < j)
            i++;
        q[j] = q[i];
    }
    q[i] = t;
    sort(l, i - 1);
    sort(i + 1, r);
}
int main()
{
    int n;
    scanf("%d", &n);
    for (int i = 0; i < 10; i++)
    {
        scanf("%d %d", &q[i].pi, &q[i].wi);
        q[i].b = q[i].pi / q[i].wi;
    }
    sort(0, 9);
    int ans = 0;
    for (int i = 0; i < 10; i++)
    {
        if (q[i].wi <= n)
        {
            ans += q[i].pi;
            n -= q[i].wi;
        }
        else
        {
            ans += n * q[i].b;
            break;
        }
    }
    printf("%d\n", ans);
    return 0;
}

7-9 商人小鑫

小鑫是个商人,当然商人最希望的就是多赚钱,小鑫也一样。

这天,他来到了一个遥远的国度。那里有着n件商品,对于第i件商品需要付出ci的价钱才能得到。当然,对于第i件商品,小鑫在自己心中有一个估价pi:代表着当他买下这件商品后带回他的国家可以卖出的价格。小鑫只能带回m件商品,你能帮他计算一下他最多能赚多少钱么?

输入格式:
第一行是n,m。( 0< m ≤ n ≤ 1000000 )

紧接着有n行,每一行有两个数 c ,p。第i行代表着ci,pi。( ci ≤ pi, 保证数据都在int范围内 )

输出格式:
输出一行一个数,代表小鑫能赚多少钱。

输入样例:
4 2
1 2
1 3
2 2
3 4

输出样例:
3

#include <stdio.h>
#include <stdlib.h>
struct node
{
    int sell_price,buy_price;
    int profit;
} a[10000000];
void qsort_profit(struct node a[],int left,int right);
//对利润进行快排;
int main()
{
    int i;
    int num_get,num_have;
    while(~scanf("%d%d",&num_have,&num_get))
    {
        for(i=0; i<num_have; i++)
        {
            scanf("%d%d",&a[i].buy_price,&a[i].sell_price);
            a[i].profit = a[i].sell_price - a[i].buy_price;
        }//输入并计算利润;
        qsort_profit(a,0,num_have);//对利润进行快排;
        int sum_profit = 0;
        for(i=0; i<num_get; i++) //计算利润总和;
            sum_profit += a[i].profit;
        printf("%d\n",sum_profit);
    }
    return 0;
}
void qsort_profit(struct node a[],int left,int right)
{
    int i = left,j = right;
    struct node key = a[left];
    //将第一个数据储存,作为标准;
    while(i>=j) return ;//递归结束的条件;
    while(i<j)
    {
        while(i<j&&a[j].profit<=key.profit)
            j--;
        a[i] = a[j];
        while(i<j&&a[i].profit>=key.profit)
            i++;
        a[j] = a[i];
    }
    a[i] = key;
    qsort_profit(a,left,i-1);
    qsort_profit(a,i+1,right);
 
}

7-10 商人的诀窍

E_star和von是中国赫赫有名的两位商人,俗话说的好无商不奸,最近E_star需要进一批苹果。可是他需要的苹果只有von才有,von的苹果都存在他的传说中很牛叉的仓库里,每个仓库都存了不同种类的苹果,而且每个仓库里的苹果的价钱不同。如果E_star想要买仓库i里的所有重量为f[i]的苹果他必须付m[i]的金钱。E_star开着他的传说中的毛驴车去拉苹果,而且他只带了N些金钱。E_star作为传说中的奸商希望用它所带的N金钱得到重量最多的苹果。你作为他最好的朋友,所以他向你求出帮助。希望你能帮忙计算出他能买到最多的苹果(这里指重量最大)。并输出最大重量。

提示:这里仅考虑仓库里苹果的重量,不考虑个数。

输入格式:
第一行包括两个非负整数N,M(分别代表E_star带的金币数,von盛苹果的仓库数量,不超过50)。

接下来有M行,每行包括两个数非负整数f[i]和m[i]分别表示第i仓库里存有重量为f[i]的苹果,如果将所有苹果买下要花费m[i]的金钱,E_star不必非要将每个仓库的苹果全部买下。

输出格式:
E_star用N的金币所能买到的最大重量的苹果的重量。结果保留三位小数。

输入样例:
20 3
25 18
24 15
15 10

输出样例:
31.500

#include <stdio.h>
struct node
{
    int f, m;
    double b;
} q[10001], t;
void sort(int l, int r) // 快排
{
    if (l >= r)
        return;
    t = q[l];
    int i = l, j = r;
    while (i < j)
    {
        while (q[j].b <= t.b && i < j)
            j--;
        q[i] = q[j];
        while (q[i].b >= t.b && i < j)
            i++;
        q[j] = q[i];
    }
    q[i] = t;
    sort(l, i - 1);
    sort(i + 1, r);
}
int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    for (int i = 0; i < m; i++)
    {
        scanf("%d %d", &q[i].f, &q[i].m);
        q[i].b = q[i].f * 1.0 / q[i].m * 1.0;
    }
    sort(0, m - 1);
    double ans = 0;
    for (int i = 0; i < m; i++)
    {
        if (q[i].m <= n)
        {
            ans += q[i].f * 1.0;
            n -= q[i].m;
        }
        else
        {
            ans += n * 1.0 * q[i].b;
            break;
        }
    }
    printf("%.3lf\n", ans);
    return 0;
}

实验6 动态规划

7-1 数字三角形问题

给定一个由n行数字组成的数字三角形如下图所示。试设计一个算法,计算出从三角形的顶至底的一条路径,使该路径经过的数字总和最大。

对于给定的由n行数字组成的数字三角形,计算从三角形的顶至底的路径经过的数字和的最大值。

输入格式:
输入数据的第1行是数字三角形的行数n,1≤n≤100。接下来n行是数字三角形各行中的数字。所有数字在0…99之间。

输出格式:
输出数据只有一个整数,表示计算出的最大值。

输入样例:
在这里给出一组输入。例如:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出样例:
30

#include <stdio.h>
#include <stdlib.h>
int main()
{
int j,n,i,d[101][101],a[101][101];
scanf("%d",&n);
for(i=1;i<=n;i++)
    for(j=1;j<=i;j++)
    scanf("%d",&d[i][j]);
for(j=1;j<=n;j++)
    a[n][j]=d[n][j];
for(i=n-1;i>=1;i--)
    for(j=1;j<=i;j++)
{
    if(a[i+1][j]>a[i+1][j+1])
        a[i][j]=a[i+1][j]+d[i][j];
    else a[i][j]=a[i+1][j+1]+d[i][j];
}
printf("%d\n",a[1][1]);
    return 0;
}

7-2 小鑫去爬山

马上就要放假了,小鑫打算去爬山。
小鑫要去爬的这座山有n个海拔区间。为了清楚描述我们可以从上到下标号1到n。
第i个区间有i个落脚点,每一个落脚点都有一个危险值。
小鑫需要在第n个海拔区间挑选一个点向上爬,爬到第1个海拔区间(也就是山顶)。他必须规划一条路径,让危险值之和最小。这样才安全的。
并不是任意两个落脚点之间都可以相互到达。我们这样定义对于第i个(i<n)区间的第j个落脚点,只有第i+1个区间的第j个和第j+1个可以到达。
你能帮助他找到最安全的路么?

输入格式:
输入数据为多组,到文件结束。
对于每一组数据,第一行有一个数,为n 。n≤100;
接下来有n行,第i行有i个数。代表第i个区间i个落脚点的危险值。
所有数据均在int范围内。

输出格式:
对于每组数据,输出一行一个数,为答案。

输入样例:
在这里给出一组输入。例如:

5
7
3 8
8 1 0
2 7 4 4
4 5 2 6 5

输出样例:
17

#include <stdio.h>
#include <stdlib.h>
int main()
{
    int n,i,j;
    int a[101][101],b[101][101];
    while(scanf("%d",&n)!=EOF)
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=i;j++)
            {
                scanf("%d",&a[i][j]);
            }
        }
        for(i=1;i<=n;i++)
        {
            b[n][i]=a[n][i];
        }
        for(i=n-1;i>=1;i--)
        {
            for(j=1;j<=i;j++)
            {
                if(b[i+1][j]<b[i+1][j+1])b[i][j]=b[i+1][j]+a[i][j];
                else b[i][j]=b[i+1][j+1]+a[i][j];
            }
        }
        printf("%d\n",b[1][1]);
    }
    return 0;
}

7-3 最长公共子序列问题

给定两个序列 X={x1,x2,…,xm} 和 Y={y1,y2,…,yn},找出X和Y的最长公共子序列。

输入格式:
输入数据有多组,每组有两行 ,每行为一个长度不超过500的字符串(输入全是大写英文字母(A,Z)),表示序列X和Y。

输出格式:
每组输出一行,表示所求得的最长公共子序列的长度,若不存在公共子序列,则输出0。

输入样例:
ABCBDAB
BDCABA

输出样例:
4

#include <stdio.h>
#include <string.h>
#define N 510
int i,j,len1,len2,c[N][N];
char x[N],y[N];
int main()
{
while(scanf("%s %s",x,y)!=EOF){
   len1=strlen(x);
   len2=strlen(y);
   for(i=0;i<=len1;i++)
   {c[i][0]=0;}
   for(j=0;j<=len2;j++) {c[0][j]=0;}
   for(i=1;i<=len1;i++){
       for(j=1;j<=len2;j++)
       {
           if(x[i-1]==y[j-1])//这里一定要注意
{
           	c[i][j]=c[i-1][j-1]+1;
		   } 
           else
           {
               if(c[i-1][j]>c[i][j-1])
               {c[i][j]=c[i-1][j];}
               else{ c[i][j]=c[i][j-1];}
           }
           
}}
    printf("%d\n",c[len1][len2]); }
    return 0;
    
}

7-4 最长公共子序列

从一个给定的串中删去(不一定连续地删去)0个或0个以上的字符,剩下地字符按原来顺序组成的串。例如:“ ”,“a”,“xb”,“aaa”,“bbb”,“xabb”,“xaaabbb”都是串“xaaabbb”的子序列。(例子中的串不包含引号。)

编程求N个非空串的最长公共子序列的长度。限制:2<=N<=100;N个串中的字符只会是数字0,1,…,9或小写英文字母a,b,…,z;每个串非空且最多含100个字符;N个串的长度的乘积不会超过30000。

输入格式:
文件第1行是一个整数T,表示测试数据的个数(1<=T<=10)。接下来有T组测试数据。各组测试数据的第1行是一个整数Ni,表示第i组数据中串的个数。各组测试数据的第2到N+1行中,每行一个串,串中不会有空格,但行首和行末可能有空格,这些空格当然不算作串的一部分。

输出格式:
输出T行,每行一个数,第i行的数表示第i组测试数据中Ni个非空串的最长公共子序列的长度。

输入样例:
1
3
ab
bc
cd

输出样例:
0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char a[110][110];//二维字符数组保存字符
int d[30010];
int len[110];//一维len保存每个字符数组的长度
int n;
int f(int l[])
{
    int i, j, index, ret, t;
    for (i = 1; i <= n; i++)
        if (l[i] == 0)//判断字符长的是否为0,为0直接以0退出
            return 0;
    //-------------------------------------------------------------
    for (index = l[n] - 1, i = n - 1; i >= 1; i--)
        index = index * len[i] + l[i] - 1;//转化为一维数组,原理有待考究(对我来说)
    if (d[index] >= 0)
        return d[index];//一但有值,直接返回
    //-------------------------------------------------------------
    for (i = 2; i <= n; i++)
        if (a[1][l[1] - 1] != a[i][l[i] - 1])
            break;//在看每个字符串的末尾(我当时看错了,,以为是倒数第二)
    if (i > n)//字符串末尾全相同
    {
        for (j = 1; j <= n; j++)
            l[j]--;
        ret = f(l) + 1;
        for (j = 1; j <= n; j++)
            l[j]++;//记得恢复
    }
    else//有不同,递归
    {
        ret = 0;
        for (j = 1; j <= n; j++)
        {
            l[j]--;//感觉类似于dfs,历遍了
            t = f(l);
            if (t > ret)
                ret = t;
            l[j]++;
        }
    }
    d[index] = ret;
    return ret;
}
//-------------------------------------------------------------
int main()
{
    int T, i;
    int l[110];//保存多维字符数组长度的动态变化
    scanf("%d", &T);
    while (T--)
    {
        scanf("%d", &n);
        for (i = 1; i <= n; i++)
        {
            scanf("%s", a[i]);
            len[i] = strlen(a[i]);
            l[i] = strlen(a[i]);
        }
        memset(d, -1, sizeof(d));
        printf("%d\n", f(l));
    }
    return 0;
}

7-5 最长上升子序列

一个数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列(a1, a2, …, aN),我们可以得到一些上升的子序列(ai1, ai2, …, aiK),这里1<= i1 < i2 < … < iK <= N。比如,对于序列(1, 7, 3, 5, 9, 4, 8),有它的一些上升子序列,如(1, 7), (3, 4, 8)等等。这些子序列中最长的长度是4,比如子序列(1, 3, 5, 8)。

你的任务,就是对于给定的序列,求出最长上升子序列的长度。

输入格式:
输入的第一行是序列的长度N (1 <= N <= 1000)。第二行给出序列中的N个整数,这些整数的取值范围都在0到10000。

输出格式:
最长上升子序列的长度。

输入样例:
在这里给出一组输入。例如:

7
1 7 3 5 9 4 8

输出样例:
在这里给出相应的输出。例如:

4

#include<stdio.h>
 
#define MAX_N 1005
 
int dp[MAX_N];
 
int main() {
    int n, a[MAX_N];
 
    // 读入序列
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
 
    // 动态规划求解
    for (int i = 1; i <= n; ++i) {
        dp[i] = 1;
        for (int j = 1; j < i; ++j) {
            if (a[j] < a[i] && dp[j]+1 > dp[i]) {
                dp[i] = dp[j] + 1;
            }
        }
    }
 
    // 找到最长上升子序列的长度
    int max_len = 0;
    for (int i = 1; i <= n; ++i) {
        if (dp[i] > max_len) max_len = dp[i];
    }
 
    // 输出结果
    printf("%d\n", max_len);
 
    return 0;
}

7-6 上升子序列

一个只包含非负整数的序列bi,当b1 < b2 < … < bS的时候,我们称这个序列是上升的。对于给定的一个序列{a1, a2, …,aN},我们可以得到一些上升的子序列{ai1, ai2, …, aiK},这里1 ≤ i1 < i2 <…< iK ≤ N。例如:对于序列{1, 7, 3, 5, 9, 4, 8},有它的一些上升子序列,如{1, 7}, {3, 4, 8}等等。这些子序列中序列和最大的是子序列{1, 3, 5, 9},它的所有元素的和为18。
对于给定的一个序列,求出它的最大的上升子序列的和。
注意:最长的上升子序列的和不一定是最大的哦。

输入格式:
输入包含多组测试数据,对于每组测试数据:
输入数据的第一行为序列的长度 n(1 ≤ n ≤ 1000),
第二行为n个非负整数 b1,b2,…,bn(0 ≤ bi ≤ 1000)。

输出格式:
对于每组测试数据,输出其最大上升子序列的和。

输入样例:
7
1 7 3 5 9 4 8

输出样例:
在这里给出相应的输出。例如:

18

#include<stdio.h>
#include<string.h>
 
#define MAX_N 1005
 
int dp[MAX_N]; // dp[i] 表示以第 i 个数结尾的最大上升子序列的和
 
int main() {
    int n, a[MAX_N];
 
    while(scanf("%d", &n) != EOF) {
        // 初始化
        memset(dp, 0, sizeof(dp));
        int max_sum = 0;
 
        // 读入序列
        for (int i = 0; i < n; ++i) scanf("%d", &a[i]);
 
        // 动态规划求解
        for (int i = 0; i < n; ++i) {
            dp[i] = a[i]; // 初始化 dp[i] 为 a[i]
            for (int j = 0; j < i; ++j) {
                if (a[j] < a[i] && dp[j] + a[i] > dp[i]) {
                    dp[i] = dp[j] + a[i];
                }
            }
            // 更新 max_sum
            if (dp[i] > max_sum) max_sum = dp[i];
        }
 
        // 输出结果
        printf("%d\n", max_sum);
    }
    return 0;
}

7-7 递归的函数

给定一个函数 f(a, b, c):
如果 a ≤ 0 或 b ≤ 0 或 c ≤ 0 返回值为 1;
如果 a > 20 或 b > 20 或 c > 20 返回值为 f(20, 20, 20);
如果 a < b 并且 b < c 返回 f(a, b, c−1) + f(a, b−1, c−1) − f(a, b−1, c);
其它情况返回 f(a−1, b, c) + f(a−1, b−1, c) + f(a−1, b, c−1) − f(a-1, b-1, c-1)。
看起来简单的一个函数?你能做对吗?

输入格式:
输入包含多组测试数据,对于每组测试数据:
输入只有一行为 3 个整数a, b, c(a, b, c < 30)。

输出格式:
对于每组测试数据,输出函数的计算结果。

输入样例:
1 1 1
2 2 2

输出样例:
2
4

#include <stdio.h>
 
int f(int a, int b, int c)
{
    if (a <= 0 || b <= 0 || c <= 0) {
        return 1;
    } else if (a > 20 || b > 20 || c > 20) {
        return f(20, 20, 20);
    } else if (a < b && b < c) {
        return f(a, b, c - 1) + f(a, b - 1, c - 1) - f(a, b - 1, c);
    } else {
        return f(a - 1, b, c) + f(a - 1, b - 1, c) + f(a - 1, b, c - 1) - f(a - 1, b - 1, c - 1);
    }
}
 
int main()
{
    int a, b, c;
    while (scanf("%d%d%d", &a, &b, &c) == 3) {
        printf("%d\n", f(a, b, c));
    }
    return 0;
}

7-8 走迷宫

有一个mn格的迷宫(表示有m行、n列),其中有可走的也有不可走的,如果用1表示可以走,0表示不可以走,输入这mn个数据和起始点、结束点(起始点和结束点都是用两个数据来描述的,分别表示这个点的行号和列号)。现在要你编程找出所有可行的道路,要求所走的路中没有重复的点,走时只能是上下左右四个方向。如果一条路都不可行,则输出相应信息(用-1表示无路)。

输入格式:
第一行是两个数m,n(1< m, n< 15),接下来是m行n列由1和0组成的数据,最后两行是起始点和结束点。

输出格式:
所有可行的路径,输出时按照左上右下的顺序。描述一个点时用(x,y)的形式,除开始点外,其他的都要用“->”表示。如果没有一条可行的路则输出-1。

输入样例:
在这里给出一组输入。例如:

5 4
1 1 0 0
1 1 1 1
0 1 1 0
1 1 0 1
1 1 1 1
1 1
5 4

输出样例:
在这里给出相应的输出。例如:

(1,1)->(1,2)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(1,2)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)
(1,1)->(1,2)->(2,2)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(1,2)->(2,2)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(2,3)->(3,3)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(3,2)->(4,2)->(4,1)->(5,1)->(5,2)->(5,3)->(5,4)
(1,1)->(2,1)->(2,2)->(3,2)->(4,2)->(5,2)->(5,3)->(5,4)

#include<stdio.h> 
#include<string.h> 
int s[20][20];//模拟地图 
int a[1000][1000];// 记录这个点是否被走过
struct node
{
	int x;
	int y;
}p[1007]; //记录从起点到终点走的方案,也是用来输出的
int n,m,k,flag;
int enx,eny;
int next[4][2]={{0,-1},{-1,0},{0,1},{1,0}}; //左上右下的顺序 
void move(int x1,int y1,int k) //k是用来记录几步的,也是方便下面用循环输出
{
	p[k].x=x1; //坐标 x ,因为经过下面if的判断,来到这里的点都是符合要求的
	p[k].y=y1; //坐标 y ,
	if(x1==enx&&y1==eny) //走到终点 
	{
		flag=1; //声明有走到终点的路线
		for(int q=0;q<=k;q++)  
		{          //把记录的都输出,把记录的连起来输出,就是一个路线 
			if(q==0) 
			{
				printf("(%d,%d)",p[q].x,p[q].y);
			}
			else printf("->(%d,%d)",p[q].x,p[q].y);	
		}
		printf("\n");
        return;
	}      
    //类似于穷举,或者平行宇宙,走一步后,又会出现4个方向可走,依次如此 
	for(int h=0;h<4;h++)
	//试试所有的方向,按照题目的要求的顺序来碰壁,因为有四个方向,所以h<4 
	{
		int nx=next[h][0]+x1;//开始加数进行位移,按照左上右下来位移 
		int ny=next[h][1]+y1;
		if(nx>0&&ny>0&&nx<=n&&ny<=m&&s[nx][ny]==1&&a[nx][ny]==0)
		{
            //只要走的坐标位置不超过地图范围,且没走过,且在迷宫上是1就可以执行 
			a[nx][ny]=1;//标记此点已经走过
			move(nx,ny,k+1);//递归一次说明走了一步就加一,因为是在k的基础上加1,函数结束时,回溯后,还是恢复原来的值。 
			//如果是用自加就在下面搭配个自减就行
			a[nx][ny]=0;//回溯 ,
		}
	}
	return;
}
int main()
{
	
	int x,y;
	while(~scanf("%d %d",&n,&m)) //多组输入 
	{
		memset(s,0,sizeof(s)); //涉及多组输出要进行初始化 
		memset(a,0,sizeof(a));
		memset(p,0,sizeof(p));
	for(int i=1;i<=n;i++) //写迷宫地图 
	{
		for(int j=1;j<=m;j++)
		{
		scanf("%d",&s[i][j]);
	    }
	}
	scanf("%d%d",&x,&y); //写入始点和终点
	scanf("%d%d",&enx,&eny);
	a[x][y]=1; //起点标记为1,因为一上来就在这个点 
	move(x,y,0);//从起点开始走 
	   if(flag==0) 
	   {
		  printf("-1\n");//如果是0说明一条路径都没有 
	   }
    }
	return 0;
}

7-9 取数字问题

给定M×N的矩阵,其中的每个元素都是-10到10之间的整数。你的任务是从左上角(1,1)走到右下角(M,N),每一步只能够向右或者向下,并且不能够走出矩阵的范围。你所经过的方格里面的数字都必须被选取,请找出一条最合适的道路,使得在路上被选取的数字之和是尽可能小的正整数。

输入格式:
输入第1行是两个整数M和N,(2<=M<=10,2<=N<=10),分别表示矩阵的行和列的数目。接下来M行,每行包括N个整数,就是矩阵中的每一行的N个元素。

输出格式:
输出只有一行,就是一个整数,表示所选道路上数字之和所能达到的最小正整数。如果不能达到任何正整数,输出-1。

输入样例:
2 2
0 2
1 0

输出样例:
1

#include <stdio.h>
#include <string.h>
#define MAXNM 14
#define oo 123456789
int a[MAXNM][MAXNM], ans;
int m, n;
void search(int i, int j, int sum)
{
    sum += a[i][j];
    if(i < m)
        search(i+1, j, sum);
    if(j < n)
        search(i, j+1, sum);
    if(i == m && j == n && sum < ans && sum > 0)
    {
        ans = sum;
    }
}
int main()
{
    int i, j, sum;
    scanf("%d %d", &m, &n);
    for(i = 1; i <= m; i++)
        for(j = 1; j <= n; j++)
            scanf("%d", &a[i][j]);
    ans = oo;
    sum = 0;
    search(1, 1, sum);
    if(ans != oo)
        printf("%d\n", ans);
    else
        printf("-1\n");
    return 0;
}

7-10 免费馅饼

都说天上不会掉馅饼,但有一天gameboy正走在回家的小径上,忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了,这馅饼别处都不掉,就掉落在他身旁的10米范围内。馅饼如果掉在了地上当然就不能吃了,所以gameboy马上卸下身上的背包去接。但由于小径两侧都不能站人,所以他只能在小径上接。由于gameboy平时老呆在房间里玩游戏,虽然在游戏中是个身手敏捷的高手,但在现实中运动神经特别迟钝,每秒种只有在移动不超过一米的范围内接住坠落的馅饼。现在给这条小径如图标上坐标:

为了使问题简化,假设在接下来的一段时间里,馅饼都掉落在0-10这11个位置。开始时gameboy站在5这个位置,因此在第一秒,他只能接到4,5,6这三个位置中期中一个位置上的馅饼。问gameboy最多可能接到多少个馅饼?(假设他的背包可以容纳无穷多个馅饼)

输入格式:
输入数据有多组。每组数据的第一行为以正整数n(0 < n < 100000),表示有n个馅饼掉在这条小径上。在结下来的n行中,每行有两个整数x,T(0 <= T < 100000),表示在第T秒有一个馅饼掉在x点上。同一秒钟在同一点上可能掉下多个馅饼。n=0时输入结束。

输出格式:
每一组输入数据对应一行输出。输出一个整数m,表示gameboy最多可能接到m个馅饼。

提示:本题的输入数据量比较大,建议用scanf读入,用cin可能会超时。

输入样例:
6
5 1
4 1
6 1
7 2
7 2
8 3
0

输出样例:
4

#include<stdio.h>
#include<string.h>
int dp[12][100005];
int pos,time;
int max(int a,int b)
{
	return a>b?a:b;
}
int main()
{
	int n;
	int a;
	while(scanf("%d",&n)!=EOF)
	{
		if(n==0)
		{
			break;
		}
		int i,j;
		int ma=0;
		memset(dp,0,sizeof(dp));
		for(i=1;i<=n;i++)
		{
			scanf("%d%d",&pos,&time);
			dp[pos][time]++;
			ma=max(time,ma);
		}
		for(i=ma-1;i>=0;i--)
		{
			dp[0][i]+=max(dp[0][i+1],dp[1][i+1]);
			dp[10][i]+=max(dp[9][i+1],dp[10][i+1]);
			for(j=1;j<10;j++)
			{
				dp[j][i]+=max(max(dp[j-1][i+1],dp[j][i+1]),dp[j+1][i+1]);
			}
		}
		printf("%d\n",dp[5][0]);
	}
}