CSP 201609-2 - 课设 火车购票

课设有这道题,粘个代码,顺便浅聊一下~

Question:

Solve:

既那就由浅到深分析:

读完题,很明显,出票方案只有两种:同排座位或者非同排座位

1.

如果不考虑时间复杂度的问题,那直接开一个 bool 型的二维数组 a[20][5] 来表示每一个座位是否已经购买。对于每次的购票指令,先遍历一次数组,对同排的剩余座位计数,判断能不能出同排的票,如果能的话就直接输出座位,不能的话就再遍历一次数组,按空余座位的顺序出票。

2.

上述方式可以解决问题,但如果数据比较刁钻,遍历两次二维数组多少有点~,所以:

注意到上面标红的位置是一个计数的过程,我们正好可以利用这个计数将二维数组转变为一维, 就是

a[ i ] = x, 表示第 i 排座位当前所剩的座位数为 x

这样做的意义是什么呢?

之前我们需要遍历的是 100 个座位, 而现在需要遍历的就只是 20 排,通过 a[ i ] 与 购票数 的大小直接判断能不能出同排座位的票,能的话就利用数学关系输出座位号,不能的话就再遍历每一排,将座位号输出

时间上会大幅缩减

 到这里,需要解决的就只剩一个问题了,通过 row[i] = x 得出座位号:

第 i 排有座的起始位置

= (i - 1)排满座 + 该排已经被买走的票的数量 + 1

= (i - 1) * 5 + ( 5 - row[ i ] ) + 1

至于具体输出座位号,如果你输出座位号的时候循环下标是从 1 开始的,1 就没必要加了,自己调整就行

3.

到此为止,这个问题就已经解决了,去CSP提交会拿满分,我的代码也就到这一步

不过我还是想继续扯两句

(1)一个购票系统,有票无票是基本判断,所以加个整体变量 sum 表示总体的剩余车票数,这很合理,顺便再加个提示

(2)能不能再画蛇添足呢?接下来就是我第一次读题想的鬼优化:

在之前的基础上,为了更快的满足出票需求,我开一个数组 pos[ i ] = x, 表示 第一个有 i 个连续座位的排是第 x 排

如果这样整的话,那基本上就不需要遍历,就直接结合 每一排剩余的座位数 和 pos[ i ],立马就能判断有没有连续座位,而且座位号也是非常容易计算出来

难点在哪呢?在数据更新上,在每一次出完票以后,需要更新所有 pos[ i ] 。如果当前排的连续座位数不够 i 个,就让pos[ i ]++,指向下一排,如果 pos[ i ] > 最大排数,就说明没连续 i 个座位的票了

不说了,读者可以顺着这个思路写一写,挺那啥的~

AC Code:

以下为同源代码,三种语言套共用一个内核,不想整活了

C++

#include <iostream>
using namespace std;
#define N 20
int n, p, exist_ticket[N+1];
void init() //初始化
{
    std::ios::sync_with_stdio(false);
    cin.tie(NULL); cout.tie(NULL);
    //初始化每一排的剩余座位数
    for(int i = 1; i <= N; i++) exist_ticket[i] = 5;
}
void solve(){   //出票
    //有连续座位
    for(int i = 1; i <= N; i++){
        if(exist_ticket[i] < p) continue;
        //计算座位号
        int x = (i-1)*5 + 5 - exist_ticket[i];
        //输出结果 更新数据 
        for(int j = 1; j <= p; j++){
            cout <<x+j <<" ";
            exist_ticket[i]--;
        }
        //得到结果,进行下一次出票
        cout <<endl; return;
    }
    //无连续座位(顺序取票)
    for(int i = 1; i <= N && p; i++){
        if(!exist_ticket[i]) continue; //该排无票
        //计算座位号
        int x = (i-1)*5 + 5 - exist_ticket[i];
        int minn = min(p, exist_ticket[i]);
        //输出结果 更新数据
        for(int j = 1; j <= minn; j++){
            cout <<x+j <<" ";
            p--, exist_ticket[i]--;
        }
    }
    cout <<endl;
}
int main(void)
{
    init(); //初始化
    cin >>n;
    while(n--){
        cin >>p; solve();
    }
    return 0;
}

Java

import java.util.Scanner;
public class Main {
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        //初始化座位信息
        int row[] = new int[21];
        for(int i = 1; i <= 20; i++) row[i] = 5;

        int n = cin.nextInt();
        while(n != 0){
            //标记是否有连续座位
            boolean IsAnd = false;
            int p = cin.nextInt();
            for(int i = 1; i <= 20; i++){
                //有连续座位
                if(row[i] >= p) {
                    IsAnd = true;
                    //计算座位号,出票
                    int x = (i - 1) * 5 + 5 - row[i];
                    for (int j = 1; j <= p; j++) {
                        //直接输出p个座位信息
                        System.out.print((x + j) + " ");
                        row[i]--;
                    }
                    break;
                }
            }
            //无连续座位
            if(IsAnd == false) {
                for (int i = 1; i <= 20 && p != 0; i++) {
                    if (row[i] == 0) continue;  //该牌无票
                    int x = (i - 1) * 5 + 5 - row[i];
                    //判断该排剩余座位是否需要全部输出
                    int minn = (p < row[i] ? p : row[i]);
                    for (int j = 1; j <= minn; j++) {
                        System.out.print((x + j) + " ");
                        row[i]--; p--;
                    }
                }
            }
            System.out.println();
            n--;
        }
    }
}

Python

#input
n = int(input())
p = input().split()
#init
a = [5 for i in range(20)]
#solve
for value in p:
    value = int(value)
    ans = False
    for i in range(20):
#have continue ticket
        if a[i] >= value:
            x = i * 5 + 5 - a[i]
            for j in range(value):
                print("%d "%(x + j + 1), end=('\n' if j == value-1 else ''))
                a[i] -= 1
            ans = True
            break
    if ans == True:
        continue
#opposite
    for i in range(20):
        if value == 0:
            break
        x = i*5 + 5 - a[i]
        minn = min(a[i], value)
        temp = minn - 1
        while temp >= 0:
            print("%d "%(x + minn - temp), end=('\n' if value == 1 else ''))
            value -= 1
            a[i] -= 1
            temp -= 1

python代码量少实锤,但是我刚用写的有点乱,还调了老长时间...

 

图片来自CCF官网,侵权请联系删除~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

UmVfX1BvaW50

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值