习题4-8 特别困的学生 UVa12108

算法竞赛入门经典(第2版)第4章 函数和递归

题4-8 特别困的学生  UVa12108

感悟。

1、从网站下载英文原题,重点在看输入输出数据与格式。

2、英文原题第一遍读下来,对参数c一直不是很理解,In this problem, we need another parameter c
(1 <=c<= a + b) to describe a student’s initial condition: the initial position in his awaken-sleeping
period.借助中文书中的中文意思,弄明白了,c是描述该学生在他周期的第c分钟,描述学生的初始状态。

3、After that, he counts the number of awaken and sleeping students (including
himself).句中的包括学生本人,学生本人是算在醒的人数里,还是睡着的人数里,表示不清楚。本人的理解是放在醒着的人数里。通过阅读英文原题中的样例表格得到印证。

4、题目读懂后,此题涉及周期性,故取模运算比较重要,先考虑该怎么编码,再动手。

5、先编写输入输出。

6、描述学生,用结构体比较方便。

7、不存在清醒时刻的初步设想:记下第一时刻状态,不存在全部清醒,那肯定存在周期性,下一个周期开始时刻与第一时刻状态相同。

8、实际编写下来,发现7、认识有问题,这种方式判断周期,有问题,故采用探测100000,若无学生都清醒,则找不到清醒时刻,打印-1。

9、提交AC,此时2016-11-10 22:05,再次做到第一次提交就AC。

附上AC代码,编译环境Dev-C++4.9.9.2

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

#define maxn 20
struct student{
    int a;
    int b;
    int c;
}stu[maxn];

int behavior[20][20];//记录所有学生的行为(一个周期)
int n;//学生人数
int now[maxn];//当前学生状态
int next[maxn];//下一时刻学生状态
int first[maxn];//第一时刻学生状态

void printnext(){
    int i;
    for(i=0;i<n;i++)
        printf("%d ",next[i]);
    printf("\n");
}

void printbehavior(){
    int i,j;
    for(i=0;i<n;i++){
        for(j=1;j<=stu[i].a+stu[i].b;j++){
            printf("%d ",behavior[i][j]);
        }
        printf("\n");
    }
}

//记下第一时刻状态,不存在全部清醒,那肯定存在周期性,下一个周期开始时刻与第一时刻状态相同
int main(){   
    int i,j,k;
    int kase=0;
    int sleep;
    int time;
    while(scanf("%d",&n)&&n){
        time=1;
        memset(behavior,0,sizeof(behavior));
        for(i=0;i<n;i++){
            scanf("%d%d%d",&stu[i].a,&stu[i].b,&stu[i].c);
            for(j=1;j<=stu[i].a;j++)
                behavior[i][j]=0;//清醒时刻标记为0
            for(;j<=stu[i].a+stu[i].b;j++)
                behavior[i][j]=1;//睡觉时刻标记为1
        }
        
        //查找学生行为处理
        for(i=0;i<n;i++){
            next[i]=behavior[i][stu[i].c];
            first[i]=next[i];
        }
        for(i=1;i<=100000;i++){//时刻
            sleep=0;
            for(j=0;j<n;j++){
                now[j]=next[j];//取出上一次下一时刻,成为当前状态
            }
            for(j=0;j<n;j++){//n个学生,统计睡觉学生数
                if(now[j]==1){
                    sleep++;
                }
            }
            if(sleep==0){//无学生睡觉
                time=i;
                break;
            }
            
     /*       //下一个周期判断,若有,则打印-1 ,实施有问题,故将该段代码进行注释
            if(i>1){
                for(j=0;j<n;j++){
                if(now[j]!=first[j])
                    break;
                }
                if(j==n){
                    time=-1;
                    printf("%d\n",i);
                    break;
                }
            }*/
            
            
            //设置下一时刻学生状态C(2,1)*C(2,1)=4
            for(j=0;j<n;j++){
                k=(stu[j].c+i)%(stu[j].a+stu[j].b);//下一时刻对应behavior位置
                if(k==0)//此举容易漏,根据题中表格可得
                    k=stu[j].a+stu[j].b;
                if(now[j]==0&&behavior[j][k]==0){//now next均清醒
                    next[j]=0; //清醒
                }else if(now[j]==1&&behavior[j][k]==0){//now睡觉 next清醒
                    next[j]=0;//清醒
                }else if(now[j]==1&&behavior[j][k]==1){//now next 均睡觉
                    next[j]=1;//睡觉
                }else if(now[j]==0&&behavior[j][k]==1){//now 清醒 next 睡觉
                    if(sleep>=(n/2+1)){//睡觉人数超过半数
                        next[j]=1;//睡觉
                    }else{
                        next[j]=0;//不能睡,清醒
                    }
                }
            }
        }
        if(i>100000)
            time=-1;
        kase++;
        printf("Case %d: %d\n",kase,time);
    }
    return 0;
}





  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值