week2实验——模拟
题目1:
烷烃基的判断。需要判断的烷烃基一共有5种。原子没有固定的编号。五种烷烃基的结构简式如下:
输入:
输入第一行为数据的组数T(1≤T≤200000)。每组数据有5行,每行是两个整数a, b(1≤a,b≤6,a ≤b)
数据保证,输入的烷烃基是以上5种之一
输出:
每组数据,输出一行,代表烷烃基的英文名
解题思路:
由于原子没有固定的编号,所以判断方法是根据每个原子邻接点的数量来判断。其中,大部分的烷烃基可以通过最高邻接点的邻接总数或者邻接点为2的原子个数一次判断。2-methylpentane和3-methylpentane在临接点的形式上是一致的,需要额外通过邻接数为3的原子的邻接点的性质(与它邻接的点邻接数为2的个数)来进行二次判断。
代码:
#include <cstdio>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
int a,b;
int linjie[7]={0,0,0,0,0,0,0};
int map[7][7];
int count[5]={0,0,0,0,0};
for(int i=1;i<=6;i++)
{
for(int j=1;j<=6;j++)
map[i][j]=0;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=5;j++)
{
scanf("%d %d",&a,&b);
linjie[a]++;
linjie[b]++;
map[a][b]=1;
map[b][a]=1;
}
for(int k=1;k<=6;k++)
{
count[linjie[k]]++;
if(linjie[k]==3)
{
for(int l=1;l<=6;l++)
{
if(map[k][l]==1&&linjie[l]==2)
{
count[0]++;
}
}
}
}
if(count[4]==1) printf("2,2-dimethylbutane\n");
else if(count[3]==2) printf("2,3-dimethylbutane\n");
else if(count[2]==4) printf("n-hexane\n");
else if(count[3]==1&&count[0]==2) printf("3-methylpentane\n");
else printf("2-methylpentane\n");
for(int p=1;p<=6;p++)
linjie[p]=0;
for(int p=0;p<=4;p++)
count[p]=0;
for(int i=1;i<=6;i++)
{
for(int j=1;j<=6;j++)
map[i][j]=0;
}
}
}
题目2:
oj评测系统的模拟,要求根据输入的有关数据,算出某人做出的题目个数以及罚时。
输入:
例如某次考试一共八道题(A,B,C,D,E,F,G,H),每个人做的题都在对应的题号下有个数量标记,负数表示该学生在该题上有过的错误提交次数但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上了一对括号,里面有个正数b,则表示该学生AC了这道题,耗去了时间a,同时曾经错误提交了b次。例子可见下方的样例输入与输出部分。
输入数据包含多行,第一行是共有的题数n(1≤n≤12)以及单位罚时m(10≤m≤20),之后的每行数据描述一个学生的信息,首先是学生的用户名(不多于10个字符的字串)其次是所有n道题的得分现状。
输出:
根据这些学生的得分现状,输出一个实时排名。实时排名显然先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。每个学生占一行,输出名字(10个字符宽),做出的题数(2个字符宽,右对齐)和时间分(4个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。数据保证可按要求的输出格式进行输出。
解题思路:
第一行的两个数直接读入即可。
从第二行开始,由于输入的数据格式比较复杂而且不统一,因此我将输入的每一行看成若干个字符串,第一个字符串为学生的名字,之后的字符串为该学生做题的情况。现在的问题是将字符转化为整数进行运算。而字符0-9的ASCII码减48即为数字0-9。总之,需要注意以下几点:
1.使用一个变量n储存该题的得分,每次读字符串得到数x(不是括号里的数),按照n*10+x-48更新n。
2.左括号代表额外罚时的出现,此时需要用另一个变量m保存罚时,更新方法同上。
3.出现符号则跳过该数据。
最后将得出的m和n求和并存到vector中并排序即可。
代码:
#include <cstdio>
#include <queue>
#include <algorithm>
#include <string.h>
using namespace std;
class student
{
public:
char *name;
int score;
int penalty;
student(char* a,int b,int c)
{
name=new char[20];
memset(name,0,20);
for(int i=0;a[i]!=0;i++)
{
name[i]=a[i];
}
score=b;
penalty=c;
};
bool operator <(const student& p) const
{
if(score!=p.score) return score>p.score;
else if(penalty!=p.penalty) return penalty<p.penalty;
else return(strcmp(name,p.name)<0);
};
};
int main()
{
int n,m;
int score=0,penalty=0;
int punish_time=0;
bool sp=false;
int thepenalty=0;
scanf("%d %d",&n,&m);
char name[20];
memset(name,0,20);
char **si;
si=new char*[n+1];
vector<student> v;
for(int i=1;i<=n;i++)
{
si[i]=new char[20];
memset(si[i],0,20);
}
while(scanf("%s",name)!=EOF)
{
for(int i=1;i<=n;i++)
{
scanf("%s",si[i]);
//printf("%s\n",si[i]);
int j=0;
while(si[i][j]!=0)
{
//printf("si[i][j]=%d\n",si[i][j]);
if(si[i][j]==45) break;
else if(si[i][j]>=48&&si[i][j]<=57&&!sp) {penalty=penalty*10+(si[i][j]-48);}
else if(si[i][j]>=48&&si[i][j]<=57&&sp) {punish_time=punish_time*10+(si[i][j]-48)*m;}
else if(si[i][j]=='(') sp=true;
else if(si[i][j]==')')
{
penalty+=punish_time;
punish_time=0;
sp=false;
}
else ;
j++;
}
if(penalty!=0) score++;
punish_time=0;
thepenalty+=penalty;
penalty=0;
sp=false;
}
student* newstudent=new student(name,score,thepenalty);
score=0;
thepenalty=0;
//printf("nn=%s\n",newstudent.name);
v.push_back(*newstudent);
memset(name,0,20);
}
sort(v.begin(),v.end());
for(int i=0;i<v.size();i++)
{
printf("%-10s %2d %4d\n",v[i].name,v[i].score,v[i].penalty);
}
return 0;
}
题目3:
发牌模拟。要求根据已知的牌堆以及发牌人的位置,按照升序输出每个玩家手中的牌。
输入:
输入包含多组数据
每组数据的第一行包含一个大写字符,表示发牌员是谁。如果该字符为‘#’则表示输入结束。
接下来有两行,每行有52个字符,表示了26张牌,两行加起来一共52张牌。每张牌都由两个字符组成,第一个字符表示花色,第二个字符表示数值。
输出:
输出多组数据发牌的结果,每组数据之后需要额外多输出一个空行!!!!!
每组数据应该由24行的组成,输出按照顺时针方向,始终先输出South Player的结果,每位玩家先输出一行即玩家名称(东南西北),接下来五行,第一行和第五行输出固定格式(见样例),第二行和第四行按顺序和格式输出数值(见样例),第三行按顺序和格式输出花色(见样例)。
样例输入/输出:
略。
解题思路:
本题的字符过多,但是由于牌(J,Q,K,A)非常的不规则,同时花色之间还有大小关系。所以为了方便,我使用了map容器,将输入的字符按照大小关系,分别映射到一个整数上。这样,在编写排序的时候,就可以通过查找map获得对应的整数,进行排序了。对于发牌员的模拟比较的简单。由于是转圈发牌,所以,可以将4个人以N为起始,按照顺时针标记为0,1,2,3。根据发牌数和起始发牌位置进行取模运算得到该牌应该发到的玩家。对于每一个玩家收到的牌,都分别存到一个vector中。再发完牌后进行排序即可。
代码:
#include <cstdio>
#include <map>
#include <queue>
#include <algorithm>
using namespace std;
map<char,int> mp;
map<char,int> position;
class card
{
public:
char color;
char point;
card(char a,char b)
{
color=a;
point=b;
};
bool operator <(const card& p) const
{
if(mp[color]==mp[p.color]) return mp[point]<mp[p.point];
else return mp[color]<mp[p.color];
};
};
int main()
{
mp['2']=2;
mp['3']=3;
mp['4']=4;
mp['5']=5;
mp['6']=6;
mp['7']=7;
mp['8']=8;
mp['9']=9;
mp['T']=10;
mp['J']=11;
mp['Q']=12;
mp['K']=13;
mp['A']=14;
mp['C']=15;
mp['D']=16;
mp['S']=17;
mp['H']=18;
position['N']=0;
position['E']=1;
position['S']=2;
position['W']=3;
vector<card> group[4];
char sender;
scanf("%c",&sender);
getchar();
int start=position[sender];
char a,b;
int count=0;
scanf("%c",&a);
while(1)
{
count++;
scanf("%c",&b);
card newcard(a,b);
if(count==26||count==52) getchar();
//printf("count=%d\na=%c,point=%c\n",count,a,newcard.point);
group[(start+count)%4].push_back(newcard);
if(count==52)
{
for(int i=0;i<4;i++)
{
vector<card>::iterator it=group[i].begin();
sort(it,it+13);
}
count=0;
for(int i=0;i<4;i++)
{
if(i==0) printf("South player:\n");
else if(i==1) printf("West player:\n");
else if(i==2) printf("North player:\n");
else if(i==3) printf("East player:\n");
for(int j=1;j<=5;j++)
{
if(j==1||j==5) printf("+---+---+---+---+---+---+---+---+---+---+---+---+---+\n");
else if(j==2||j==4)
{
for(int k=0;k<13;k++)
{
printf("|%c %c",group[(2+i)%4][k].point,group[(2+i)%4][k].point);
}
printf("|\n");
}
else
{
for(int k=0;k<13;k++)
{
printf("| %c ",group[(2+i)%4][k].color);
}
printf("|\n");
}
}
}
printf("\n");
for(int i=0;i<4;i++)
{
group[i].clear();
}
count=0;
scanf("%c",&sender);
getchar();
start=position[sender];
if(sender=='#') break;
}
scanf("%c",&a);
}
return 0;
}
总结:
三道小模拟,题目不算很难。通过这三个题,我对map,vector等C++STL容器有了更加深入的理解。自我感觉对模拟题还需要加强,做的时候不是很顺。虽然思路简单,但打起代码的时候还是不太顺利。以后还是要多练。
上一篇: Spring Aop 源码解析
下一篇: 堡垒机Jumpserver安装