程序设计week9作业题

程序设计week9作业题

to sum up
本周主要聚焦于大模拟的一些普适性方法,主要是练习从外到内、从浅入深的去设计解题框架设计。作业题是两道模拟题,一道是比较复杂的目录管理器,也是课上的例题,另一道是打牌题,比较简单,除此之外还有一道签到题,联系独立思考。现进行一一列举。

C题 签到题 长椅人数

SDUQD 旁边的滨海公园有 x 条长凳。第 i 个长凳上坐着 a_i 个人。这时候又有 y 个人将来到公园,他们将选择坐在某些公园中的长凳上,那么当这 y 个人坐下后,记k = 所有椅子上的人数的最大值,那么k可能的最大值mx和最小值mn分别是多少。

Sample input and output

input

第一行包含一个整数 x (1 <= x <= 100) 表示公园中长椅的数目
第二行包含一个整数 y (1 <= y <= 1000) 表示有 y 个人来到公园
接下来 x 个整数 a_i (1<=a_i<=100),表示初始时公园长椅上坐着的人数

3
7
1
6
1
output

输出 mn 和 mx

6 13

解题思路及代码

这道题思路非常简单,但有很多细节问题需要考虑清楚。奈何我由于急着下手导致出现了很多漏洞。这么简单的题错了这么多次也是十分丢人了。
在这里插入图片描述
首先k可能的最大值mx,很简单,就是原有长椅上的最多人数maxn加新来的总人数。
主要需要详细考虑的就是mn的值。需要首先判断,原有长椅上的最多人数maxn是否能继续为最多人数。可以想象,当第二批人来之后,若maxn大于等于每个长椅上人数的平均数时候,即 设长椅上原有总人数为sum,当sum+y<=maxnx时,mn的值即为maxn。若sum+y>maxnx,则mn为每个长椅上的人数平均数(尾数处理方法采用进一法)。

#include <iostream>
using namespace std;
int a[105];
int N,M;
int mx,mn;
int main()
{
    while(cin>>N)
    {
        cin>>M;
        mx=0;
        int cnt=0;
        //cnt计算原来椅子上的总人数,mx记录原来椅子上的最大人数
        for(int i=0;i<N;i++) {
            cin >> a[i];
            mx = (a[i] > mx) ? a[i] : mx;
            cnt+=a[i];
        }
        //判断椅子上的最大人数是否依然可以为mx
        int tmp=mx*N-cnt;   //如果每个椅子最多做mx个人,还有tmp个空位
        if(M<=tmp)  mn=mx;
        else
        {
            mn=(cnt+M)/N;
            if((cnt+M)%N!=0)
                mn++;
        }

        mx+=M;
        cout<<mn<<' '<<mx<<endl;
    }
    return 0;
}

B题 签到题 长椅人数

最近,东东沉迷于打牌。所以他找到 HRZ、ZJM 等人和他一起打牌。由于人数众多,东东稍微修改了亿下游戏规则:

所有扑克牌只按数字来算大小,忽略花色。
每张扑克牌的大小由一个值表示。A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, K 分别指代 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13。
每个玩家抽得 5 张扑克牌,组成一手牌!(每种扑克牌的张数是无限的,你不用担心,东东家里有无数副扑克牌)
理所当然地,一手牌是有不同类型,并且有大小之分的。

举个栗子,现在东东的 “一手牌”(记为 α),瑞神的 “一手牌”(记为 β),要么 α > β,要么 α < β,要么 α = β。

那么这两个 “一手牌”,如何进行比较大小呢?首先对于不同类型的一手牌,其值的大小即下面的标号;对于同类型的一手牌,根据组成这手牌的 5 张牌不同,其值不同。下面依次列举了这手牌的形成规则:

大牌:这手牌不符合下面任一个形成规则。如果 α 和 β 都是大牌,那么定义它们的大小为组成这手牌的 5 张牌的大小总和。

对子:5 张牌中有 2 张牌的值相等。如果 α 和 β 都是对子,比较这个 “对子” 的大小,如果 α 和 β 的 “对子” 大小相等,那么比较剩下 3 张牌的总和。

两对:5 张牌中有两个不同的对子。如果 α 和 β 都是两对,先比较双方较大的那个对子,如果相等,再比较双方较小的那个对子,如果还相等,只能比较 5 张牌中的最后那张牌组不成对子的牌。

三个:5 张牌中有 3 张牌的值相等。如果 α 和 β 都是 “三个”,比较这个 “三个” 的大小,如果 α 和 β 的 “三个” 大小相等,那么比较剩下 2 张牌的总和。

三带二:5 张牌中有 3 张牌的值相等,另外 2 张牌值也相等。如果 α 和 β 都是 “三带二”,先比较它们的 “三个” 的大小,如果相等,再比较 “对子” 的大小。

炸弹:5 张牌中有 4 张牌的值相等。如果 α 和 β 都是 “炸弹”,比较 “炸弹” 的大小,如果相等,比较剩下那张牌的大小。

顺子:5 张牌中形成 x, x+1, x+2, x+3, x+4。如果 α 和 β 都是 “顺子”,直接比较两个顺子的最大值。

龙顺:5 张牌分别为 10、J、Q、K、A。

作为一个称职的魔法师,东东得知了全场人手里 5 张牌的情况。他现在要输出一个排行榜。排行榜按照选手们的 “一手牌” 大小进行排序,如果两个选手的牌相等,那么人名字典序小的排在前面。

不料,此时一束宇宙射线扫过,为了躲避宇宙射线,东东慌乱中清空了他脑中的 Cache。请你告诉东东,全场人的排名

Sample input and output

input

输入包含多组数据。每组输入开头一个整数 n (1 <= n <= 1e5),表明全场共多少人。
随后是 n 行,每行一个字符串 s1 和 s2 (1 <= |s1|,|s2| <= 10), s1 是对应人的名字,s2 是他手里的牌情况。

3
DongDong AAA109
ZJM 678910
Hrz 678910
output

对于每组测试数据,输出 n 行,即这次全场人的排名。

Hrz
ZJM
DongDong

解题思路及代码

模拟排序题。设置比赛选手类,含有string类型 姓名name ,string 类型 手牌cards,double类型分数score三个变量值。最后重写比较函数cmp,首先比较分数,分数相同的比较name。
关于score的设置,整数部分即类型的编号值,小数部分为具体手牌值。如同样是打牌类型,整数部分为1,小数部分为五张手牌和除以100。由此进行不同类型手牌和同类型不同值手牌的大小比较。

#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
const int MAXN=1e5+100;
int N;
string str1,str2;

struct player
{
public:
    string name;
    string cards;
    double score=0.0;
};
vector<player> Players;

bool cmp(player a,player b)
{
    if(a.score > b.score)
        return true;
    else if(a.score == b.score)
    {
        /*for(int i=0;i<a.name.size() && i<b.name.size();i++)
        {
            if(a.name[i]!=b.name[i])
                return a.name[i]<b.name[i];
        }*/
        return a.name<b.name;
    } else
        return false;
}

void init()
{
    Players.clear();
    for(int i=0;i<N;i++)
    {
        cin>>str1;
        cin>>str2;
        player p;
        p.name=str1;
        p.cards=str2;
        Players.push_back(p);
    }
}

int value(char a)
{
    if(a=='A') return 1;
    if(a=='J') return 11;
    if(a=='Q') return 12;
    if(a=='K') return 13;
    if(a=='1') return 10;
    else
        return a-48;
}

double result(string str)
{
    int a[15]={0};
    vector<int> val;
    int tar=0;
    for(int i=0;i<str.size();i++)
    {
        tar=0;
        if(str[i]=='0')
            continue;
        int tmp=value(str[i]);
        a[tmp]++;

        for(int j=0;j<val.size();j++)
            if(val[j]==tmp) tar=1;
        if(tar==0)  val.push_back(tmp);
//        cout<<tmp<<' '<<val.size()<<endl;
    }
    //cout<<endl;
    sort(val.begin(),val.end());
    /*for(int i=0;i<val.size();i++)
        cout<<val[i]<<' ';
    cout<<endl;*/
    //a[i] 存储了值为i的牌的张数,val中从小到大存储了牌的种类。
    if(val.size()==5 && val.front()==1 && val[1]==10)
        return 800.0;
    else if(val.size()==5 && val.back()-val.front()==4)
    {
        //顺子
        double tail=(double)val.back();
        return 700+tail;
    }
    else if(val.size()==2 && (a[val.front()]==4 || a[val.front()]==1))
    {
        //炸弹
        double tail=0;
        if(a[val.front()]==4)
        {
            tail+=(double)val.front();
            tail+=(double)val.back()/100;
        } else{
            tail+=(double)val.back();
            tail+=(double)val.front()/100;
        }
        return 600+tail;
    }
    else if(val.size()==2 && (a[val.front()]==2 || a[val.front()]==3))
    {
        //三带二
        double tail=0;
        if(a[val.front()]==3)
        {
            tail+=(double)val.front();
            tail+=(double)val.back()/100;
        } else{
            tail+=(double)val.back();
            tail+=(double)val.front()/100;
        }
        return 500+tail;
    }
    else if(val.size()==3 && (a[val.front()]*a[val.back()]==1 || a[val.front()]*a[val.back()]==3))
    {
        //三个
        int tri=0,sum=0;
        for(int i=0;i<3;i++)
        {
            if(a[val[i]]==3) tri=val[i];
            else sum+=val[i];
        }

        double tail=0;
        tail+=(double)tri;
        tail+=(double)sum/100;
        return 400+tail;
    }
    else if(val.size()==3 && (a[val.front()]*a[val.back()]==2 || a[val.front()]*a[val.back()]==4))
    {
        //两对
        double b[2]={0};
        int targ=1;
        double single=0;
        for(int i=0;i<3;i++)
        {
            if(a[val[i]]==2) b[targ--]=val[i];
            else single=val[i];
        }
        double tail=0.0;
        tail+=b[0];
        tail+=b[1]/20;
        tail+=single/400;
        return 300+tail;
    }
    else if(val.size()==4)
    {
        //对子
        double tail=0;
        int sum=0;
        int targ=0;
        for(int i=0;i<4;i++)
        {
            if(a[val[i]]==2) targ=val[i];
            else sum+=val[i];
        }
        tail+=(double)targ;
        tail+=(double)sum/100;
        return 200+tail;
    } else
    {
        // 大牌
        int sum=0;
        for(int i=0;i<5;i++)
            sum+=val[i];
        double tail=0;
        tail+=(double)sum;
        return 100+tail;
    }
}

void play()
{
    for(int i=0;i<N;i++)
        Players[i].score=result(Players[i].cards);

    sort(Players.begin(),Players.end(),cmp);
}

void display()
{
    /*for(int i=0;i<N;i++)
        cout<<Players[i].name<<' '<<Players[i].score<<endl;*/
    for(int i=0;i<N-1;i++)
        cout<<Players[i].name<<endl;
    cout<<Players[N-1].name;
}

int main()
{
    while(cin>>N)
    {
        init();
        play();
        display();
    }
    return 0;
}

A题 咕咕东的目录管理器

初始时,咕咕东的硬盘是空的,命令行的当前目录为根目录 root。
目录管理器可以理解为要维护一棵有根树结构,每个目录的儿子必须保持字典序。
在这里插入图片描述
现在咕咕东可以在命令行下执行以下表格中描述的命令:
在这里插入图片描述

Sample input and output

input

输入文件包含多组测试数据,第一行输入一个整数表示测试数据的组数 T (T <= 20);
每组测试数据的第一行输入一个整数表示该组测试数据的命令总数 Q (Q <= 1e5);
每组测试数据的 2 ~ Q+1 行为具体的操作 (MKDIR、RM 操作总数不超过 5000);

1
22
MKDIR dira
CD dirb
CD dira
MKDIR a
MKDIR b
MKDIR c
CD ..
MKDIR dirb
CD dirb
MKDIR x
CD ..
MKDIR dirc
CD dirc
MKDIR y
CD ..
SZ
LS
TREE
RM dira
TREE
UNDO
TREE
output

每组测试数据的输出结果间需要输出一行空行。注意大小写敏感。

OK
ERR
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
OK
9
dira
dirb
dirc
root
dira
a
b
c
dirb
x
dirc
y
OK
root
dirb
x
dirc
y
OK
root
dira
a
b
c
dirb
x
dirc
y

解题思路及代码

#include<iostream>
#include<string>
#include<map>
#include<vector>
using namespace std;
int T;
const string CMD_NAME[7] = { "MKDIR","RM","CD","SZ","LS","TREE","UNDO" };
string temp;

struct directory {
    string _name;
    map<string, directory*> _children;
    directory* parent;
    int subtreesize=0;
    bool update;
    vector<string> ten;
    directory(string name, directory* parent)
    {
        this->_name = name;
        this->parent = parent;
        this->subtreesize = 1;
    }

public:
    bool addchild(directory* ch)
    {
        if (_children.find(ch->_name) != _children.end())
        {
            return false;
        }
        else
        {
            _children[ch->_name] = ch;
            maintain(+ch->subtreesize);
            return true;
        }
    }
    directory* getchild(string s)
    {
        auto it = _children.find(s);
        if (it == _children.end())return NULL;
        else return it->second;
    }
    directory* mkdir(string name)
    {
        if (_children.find(name) != _children.end())
            return NULL;
        else
        {
            directory* ch = new directory(name, this);
            _children[name] = ch;
            maintain(+1);
            return ch;
        }
    }
    directory* rm(string name)
    {
        auto it = _children.find(name);
        if (it == _children.end())
            return NULL;
        else
        {
            directory* iter = it->second;
            maintain(-1 * it->second->subtreesize);
            it = _children.erase(it);
            return iter;
        }
    }
    directory* cd(string name)
    {
        if (name == "..")
        {
            return this->parent;
        }
        else
        {
            return getchild(name);
        }
    }
    void maintain(int d)
    {
        update = true;
        subtreesize = subtreesize + d;
        if (parent != NULL)
        {
            parent->maintain(d);
        }
    }
    void sz()
    {
        printf("%d\n", this->subtreesize);
    }
    void ls()
    {
        int sz = _children.size();
        if (sz == 0)printf("EMPTY\n");
        else if (sz <= 10)
            for(auto& entry : _children)
                printf("%s\n", entry.first.c_str());
        else
        {
            auto it = _children.begin();
            for (int i = 0; i < 5; i++, it++)
                printf("%s\n", it->first.c_str());
            printf("...\n");
            it = _children.end();
            for (int i = 0; i < 5; i++)it--;
            for (int i = 0; i < 5; i++, it++)
                printf("%s\n", it->first.c_str());
        }
    }
    void tree()
    {
        if (subtreesize == 1)printf("EMPTY\n");
        else if (subtreesize <= 10)
        {
            if (this->update)
            {
                ten.clear();
                treeall(&ten);
                this->update = false;
            }
            for (int i = 0; i < ten.size(); i++)
                printf("%s\n", ten.at(i).c_str());
        }
        else {
            if (this->update)
            {
                ten.clear();
                treefirst(5, &ten);
                Ltree(5, &ten);
                this->update = false;
            }
            for (int i = 0; i < 5; i++)
                printf("%s\n", ten.at(i).c_str());
            printf("...\n");
            for (int i = 9; i >= 5; i--)
                printf("%s\n", ten.at(i).c_str());
        }
    }
private:
    void treeall(vector<string>* bar)
    {
        bar->push_back(_name);
        for (auto& entry : _children)
            entry.second->treeall(bar);
    }
    void treefirst(int num, vector<string>* bar)
    {
        bar->push_back(_name);
        if (--num == 0)return;
        int n = _children.size();
        auto it = _children.begin();
        while (n--)
        {
            int sts = it->second->subtreesize;
            if (sts >= num) {
                it->second->treefirst(num, bar);
                return;
            }
            else {
                it->second->treefirst(sts, bar);
                num -= sts;
            }
            it++;
        }
    }
    void Ltree(int num, vector<string>* bar)
    {
        int n = _children.size();
        auto it = _children.end();
        while (n--)
        {
            it--;
            int sts = it->second->subtreesize;
            if (sts >= num) {
                it->second->Ltree(num, bar);
                return;
            }
            else {
                it->second->Ltree(sts, bar);
                num -= sts;
            }
        }
        bar->push_back(_name);
    }
};

struct command {
    int type;
    directory* tempdir;
    string arg;
    command(string s)
    {
        for (int i = 0; i < 7; i++)
        {
            if (CMD_NAME[i] == s)
            {
                type = i;
                if (type < 3)
                    cin >> temp, arg = temp;
                return ;
            }
        }
    }
};

void solve() {
    int Q;
    cin >> Q;
    directory* now = new directory("root", NULL);
    vector<command*>cmdlist;
    for (int i = 0; i < Q; i++)
    {
        cin >> temp;
        command* cmd = new command(temp);
        directory* t;
        bool suc = false;
        switch (cmd->type)
        {
            case 0://MKDIR
                cmd->tempdir = now->mkdir(cmd->arg);
                if (cmd->tempdir == NULL)
                    printf("ERR\n");
                else {
                    printf("OK\n");
                    cmdlist.push_back(cmd);
                }
                break;
            case 1:
                cmd->tempdir = now->rm(cmd->arg);
                if (cmd->tempdir == NULL)
                    printf("ERR\n");
                else {
                    printf("OK\n");
                    cmdlist.push_back(cmd);
                }
                break;
            case 2://CD.
                t = now->cd(cmd->arg);
                if (t == NULL)
                    printf("ERR\n");
                else {
                    printf("OK\n");
                    cmd->tempdir = now;
                    now = t;
                    cmdlist.push_back(cmd);
                }break;
            case 3://SZ
                now->sz(); break;
            case 4://LS
                now->ls(); break;
            case 5://TREE
                now->tree(); break;
            case 6://UNDO
            {
                while (!suc && cmdlist.size())
                {
                    cmd = cmdlist.back();
                    cmdlist.pop_back();
                    switch (cmd->type)
                    {
                        case 0:suc = now->rm(cmd->arg) != NULL; break;
                        case 1:suc = now->addchild(cmd->tempdir);  break;
                        case 2:now = cmd->tempdir; suc = true; break;
                        default:
                            break;
                    }
                }
                printf(suc ? "OK\n" : "ERR\n");
                break;
            }
        }
    }
}

int main()
{
    scanf("%d",&T);
    while (T--)
        solve();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值