程序设计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;
}