【A题_化学】
题目:
化学很神奇,以下是烷烃基。
(注:为了表示方便,暂且按先从左到右再从上到下的顺序将其表示为12345号)
假设如上图,这个烷烃基有6个原子和5个化学键,6个原子分别标号1~6,然后用一对数字 a,b 表示原子a和原子b间有一个化学键。这样通过5行a,b可以描述一个烷烃基。
你的任务是甄别烷烃基的类别。
思路:
既然是判别不同的种类,首先应该做的就是快速发现其中的不同,然后分类判别。观察比较容易得出的结果是 1 号有4 个点连接了两根线、两个点只有一根线;4号2个点3根线、四个点1根线;5号1个点4根线 、1个点两根线、两个点一根线;在这方面2 和3 号相同,因此针对这两个要附加判别标准,继续观察,同有3根线的原子相连的原子,所拥有的连线的一个是4 一个是5,据此可判别所有的类别。
根据以上判别原则,为判别145号建立一个可建立一个二维数组,用以表示每个种类拥有不同连线的原子个数,可以直接判断。针对2 3号,利用散列技术,将每个原子所连接的原子表示出来,然后计算特殊点邻接的原子所拥有的总连线数。
总结:
这次的思路不好的地方是太麻烦了,针对2 3 号而建立的哈希表,却要在每一组元素输入的时候都要做一遍,这样就额外耗费了时间和空间。但是因为单纯用数组或者哈希表的话,(因本人还是太菜)暂时没有想到可以分辨出来的方法。
还有一点需要提的是哈希链表每一个桶插入的元素里,如果元素需要比较大小的话,可以遍历,但是如果对后边的元素没有大小要求的话,用头插法会更简洁一点。这里记录一个比较简短的代码。
P(int xx,P *p){ //结构体里
y=xx;
next=p;
}
/****************************/
now->next= new P(p.y, now->next);//now 是链表头指针
//意为将now原本的next 赋给新指针,完成连接,然后将now->next 指向新指针
最后一个相对省时的方案就是由于我们已知最大连线数就是3 因此当增加到3的时候就将此时的编号保存下来,之后判断的时候就不用再进行遍历。
代码:
#include<stdio.h>
#include<iostream>
using namespace std;
int B[7]={0};
int A[7]={0};
struct P{
int x;
int y;
P * next;
P(){
y=0;
next =NULL;
}
P(int xx,P *p){
y=xx;
next=p;
}
};
int main()
{
int n;
scanf("%d",&n);
int flag;
for(int i=0;i<n;i++)
{
P * table= new P[7];
for(int j=0;j<5;j++)
{
P p;
scanf("%d%d",&p.x,&p.y);
int k;
B[p.x]++;
B[p.y]++;
P *now= &table[p.x];
now->next= new P(p.y, now->next);
table[p.x].y++;
if(table[p.x].y==3){
flag=p.x;
}
P *nowb= &table[p.y];
nowb->next= new P(p.x, nowb->next);
table[p.y].y++;
if(table[p.y].y==3){
flag=p.y;
}
}
for(int i=1;i<7;i++)
{
if(B[i]==1) A[1]++;
else if(B[i]==2) A[2]++;
else if(B[i]==3) A[3]++;
else if(B[i]==4) A[4]++;
}
if(A[2]==4&&A[1]==2) printf("n-hexane\n");
else if(A[1]==4&&A[3]==2) printf("2,3-dimethylbutane\n");
else if(A[1]==4&&A[2]==1&&A[4]==1) printf("2,2-dimethylbutane\n");
else{ // 1 1 3 2 2 1
// 1 2 3 1 2 1
P *t=&table[flag];
int count=0;
while(t->next!=NULL){
int tt=t->next->y;
count+=table[tt].y;
t=t->next;
}
//cout<<count<<"&&"<<endl;
if(count==4) printf("2-methylpentane\n");
else printf("3-methylpentane\n");
}
for(int i=0;i<7;i++){
A[i]=B[i]=0;
table[i].y=0;
}
delete table;
}
return 0;
}
【B题_输出实时排名】
题目:例如某次考试一共八道题(A,B,C,D,E,F,G,H),每个人做的题都在对应的题号下有个数量标记,负数表示该学生在该题上有过的错误提交次数但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上了一对括号,里面有个正数b,则表示该学生AC了这道题,耗去了时间a,同时曾经错误提交了b次。例子可见下方的样例输入与输出部分。
input:
输入数据包含多行,第一行是共有的题数n(1≤n≤12)以及单位罚时m(10≤m≤20),之后的每行数据描述一个学生的信息,首先是学生的用户名(不多于10个字符的字串)其次是所有n道题的得分现状,其描述采用问题描述中的数量标记的格式,见上面的表格。
output:
根据这些学生的得分现状,输出一个实时排名。实时排名显然先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。每个学生占一行,输出名字(10个字符宽),做出的题数(2个字符宽,右对齐)和时间分(4个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。数据保证可按要求的输出格式进行输出。
思路:尽管这个题的题干比较长,但是容易看出来这就是一个多关键字排序问题,其中比较重要的有两个部分,一个是对输入字符串的处理,另一个就是格式化输出;
总结:
字符串的输入处理:
每一个 同学拥有n 组数据,n组中的数据格式是不相同的,因此用 cin 输入字符串遇到空格就是的特性,每一小组都当作字符串处理。每一组可能拥有三种情况,正数、负数、正数带罚时。第一个判断就是有没有罚时,就是有没有括号存在,利用find 函数找出字符串中括号的位置,然后利用字符串的剪切获得其中数据,然后根据情况一次处理。这里保存一种将字符串类型转化成数字的方法:
stringstream ss; //引入字符串流
int int_a; //将字符串转换成数字
ss<<a;
ss>>int_a;
格式化的输出:
这里主要是输出的长度和左右对齐的问题,再次查找资料得到格式化输出的一般总结:
printf的一般形式为printf(“格式控制字符串”,输出列表),格式控制字符串形式为:[标志][输出最小宽度][.精度][长度]类型。
其中方括号[]中的项为可选项。 各项的意义介绍如下:
1)类型:类型字符用以表示输出数据的类型,其格式符和意义如下表所示:
d 以十进制形式输出带符号整数(正数不输出符号)
o 以八进制形式输出无符号整数(不输出前缀 0)
x,X 以十六进制形式输出无符号整数(不输出前缀 Ox)
u 以十进制形式输出无符号整数
f 以小数形式输出单、双精度实数
e,E 以指数形式输出单、双精度实数
g,G 以%f 或%e 中较短的输出宽度输出单、双精度实数
c 输出单个字符
s 输出字符串
2)标志:标志字符为-、+、#、空格四种,其意义下表所示:
‘-’结果左对齐,右边填空格
‘+’ 输出符号(正号或负号)
‘空格 输出值为正时冠以空格,为负时冠以负号
‘#’ 对 c,s,d,u类无影响;对 o 类,在输出时加前缀 o;对 x 类,在输出时加前缀 0x;对 e,g,f 类当结果有小数时才给出小数点
3)输出最小宽度:用十进制整数来表示输出的最少位数。 若实际位数多于定义的宽度,则按实际位数输出,若实际位数少于定义的宽度则补以空格或 0。
4)精度:精度格式符以“.”开头,后跟十进制整数。本项的意义是:如果输出数字,则表示小数的位数;如果输出的是字符,则表示输出字符的个数;若实际位数大于所定义的精度数,则截去超过的部分。
5)长度:长度格式符为 h,l 两种,h 表示按短整型量输出,l 表示按长整型量输出。
sort 函数:
在这个实验中新用了sort 函数,在这里讲一下对sort 的粗浅理解;
一般形式是void sort(begin,end,compare)
begin end 表示排序的起始和结束位置。compare 则是定义了比较方法,默认升序,如果需要其他比较方法的话,可以自定义排序方法,sort 的复杂度是n*log(n)
代码:
#include<iostream>
#include<vector>
#include<algorithm>
#include<string>
#include<sstream>
#include<cstdlib>
#include<stdlib.h>
using namespace std;
struct student{
string name;
int acNum;
int penalty;
};
int compare(student stu1, student stu2){
if(stu1.acNum!=stu2.acNum){
return stu1.acNum > stu2.acNum;
}
else{
if(stu1.penalty!=stu2.penalty){
return stu1.penalty < stu2.penalty;
}
else{
return stu1.name < stu2.name;
}
}
}
int main()
{
int n,m;
scanf("%d%d",&n,&m);
vector<student> v;
string name;
while(cin>>name)
{
student s;
int ac=0,pen=0;
for(int i=0;i<n;i++){
string a;
cin>>a; //以空格结束
int start=a.find('(');
if(start==-1){
stringstream ss;
int int_a; //将字符串转换成数字
ss<<a;
ss>>int_a;
if(int_a>0)
{
ac++;
pen=pen+int_a;
}
}
else {
ac++;
int end =a.find(')');
int wrongNum ;
stringstream ss;
ss<<a.substr(start+1,end-start-1);
ss>>wrongNum;
pen=pen+wrongNum*m;
int b;
ss.clear();
ss<<a.substr(0,start);
ss>>b;
pen=pen+b;
//cout<<" "<<a.substr(0,start)<<" "<<wrongNum<<" "<<b<<" "<<pen<<endl;
} //输入处理
//cout<<pen<<endl;
}
s.name=name;
s.acNum=ac;
s.penalty=pen;
v.push_back(s);
}
sort(v.begin(), v.end(), compare);
for(int i=0; i<v.size(); i++){
student s = v.at(i);
printf("%-10s %2d %4d\n", s.name.c_str(), s.acNum, s.penalty);
}
return 0;
}
【C题_发牌】
题目:
瑞神HRZ因为疫情在家闲得无聊,同时他又非常厉害,所有的课对他来说都是水一水就能拿A+,所以他无聊,找来了另外三个人:咕咕东,腾神以及zjm来打牌(天下苦瑞神久矣)。
显然,牌局由四个人构成,围成一圈。我们称四个方向为北 东 南 西。对应的英文是North,East,South,West。游戏一共由一副扑克,也就是52张构成。开始,我们指定一位发牌员(东南西北中的一个,用英文首字母标识)开始发牌,发牌顺序为顺时针,发牌员第一个不发自己,而是发他的下一个人(顺时针的下一个人)。这样,每个人都会拿到13张牌。
现在我们定义牌的顺序,首先,花色是(梅花)<(方片)<(黑桃)<(红桃),(输入时,我们用C,D,S,H分别表示梅花,方片,黑桃,红桃,即其单词首字母)。对于牌面的值,我们规定2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < T < J < Q < K < A。
现在你作为上帝,你要从小到大排序每个人手中的牌,并按照给定格式输出。(具体格式见输出描述和样例输出)。
input:
输入包含多组数据
每组数据的第一行包含一个大写字符,表示发牌员是谁。如果该字符为‘#’则表示输入结束。
接下来有两行,每行有52个字符,表示了26张牌,两行加起来一共52张牌。每张牌都由两个字符组成,第一个字符表示花色,第二个字符表示数值。
output:
输出多组数据发牌的结果,每组数据之后需要额外多输出一个空行!!!!!
每组数据应该由24行的组成,输出按照顺时针方向,始终先输出South Player的结果,每位玩家先输出一行即玩家名称(东南西北),接下来五行,第一行和第五行输出固定格式(见样例),第二行和第四行按顺序和格式输出数值(见样例),第三行按顺序和格式输出花色(见样例)。
思路:
首先可以明确的几点是:(1)根据发牌人的位置,第一次拿到牌的人是不同的,结果SWNE的输出顺序确是一样的。并且尽管顺序不同,但是构成了一个循环,因此要着重表示的就是如何记录每个人手中的牌。(2)题目中由于加入了TJQKCDSH ,加大了比较的难度,但本质上仍然是一个比较问题。(3)至于输出方面一看就让人很头疼,但是仔细观察的话可是发现输出的格式也是极有规律的。因此这个题就是建立一个二维数组,表示每个人手里的牌,首先按照规则输入处理得到每个人手里的牌是什么,然后分别对每个人手里的牌进行排序,最后就是按照指定的格式输出。
**总结:**根据这个思路,本次实验的重难点,就有两个部分组成
(1)怎样表示每个人手里的牌是什么
这里使用的就是一种轮换的方法;
if(c=='N') num=3; //决定第一个发牌的人 3 0 1 2
else if(c=='E') num=0; //0 1 2 3
else if(c=='S') num=1; //东南西北 //1 2 3 0
else num=2; //2 3 0 1
for(i=0;i<13;i++)
for(j=0;j<4;j++) //13次每次4人
cin>>a[(j+num)%4][i].x>>a[(j+num)%4][i].y;
每次循环的人数都是4 ,因此以4 为底,由于结果的输出是SWNE的顺序,为输出方便使SWNE的顺序正好使0 1 2 3 而这个的实现方法就是根据发牌的j 附加一个值num 达到这种效果。
(2)如何进行排序
同上使用sort 函数,因此关键问题就转换成了如何定义比较方法。这里采用的比较方法,并没有太多的技巧,先根据花色,然后根据数值比较。这也是比较冗杂的一个地方。盲猜可以用map转换,但是具体的细节还没有想清楚。
代码:
#include<iostream>
//#include<cmath>
#include<algorithm>
#include<stdio.h>
using namespace std;
struct P
{
char x,y;
}a[4][13]; //结构体二维数组
bool compare(struct P d,struct P e)
{
if(d.x==e.x) //花色相等 //CDSH
{
if(d.y>='2'&&d.y<='9'&&e.y>='2'&&e.y<='9') return d.y>e.y;
else if(d.y=='T'&&e.y>='2'&&e.y<='9') return true;
else if(d.y=='J'&&(e.y=='T'||(e.y>='2'&&e.y<='9'))) return true;
else if(d.y=='Q'&&((e.y>='2'&&e.y<='9')||e.y=='T'||e.y=='J')) return true;
else if(d.y=='K'&&((e.y>='2'&&e.y<='9')||e.y=='T'||e.y=='J'||e.y=='Q')) return true;
else if(d.y=='A') return true;
return false;
}
if(d.x=='H') return true; //花色不同的比较 True 表示d>e
else if(d.x=='S'){
if(e.x<'S'&&e.x!='H') return true;
return false;
}
else if(d.x=='D'){
if(e.x<'D') return true;
return false;
}
else return false;
}
int main()
{
int i,j,k;
char c;
int num;
scanf("%c",&c);
getchar();
while(c!='#')
{
if(c=='N') num=3; //决定第一个发牌的人 3 0 1 2
else if(c=='E') num=0; //0 1 2 3
else if(c=='S') num=1; //东南西北 //1 2 3 0
else num=2; //2 3 0 1
for(i=0;i<13;i++)
for(j=0;j<4;j++) //13次每次4人
cin>>a[(j+num)%4][i].x>>a[(j+num)%4][i].y;
for(i=0;i<4;i++)
sort(a[i],a[i]+13,compare);//排序
for(i=0;i<4;i++) //输出
{
if(i==0) cout<<"South "; //南西北东 0 1 2 3
else if(i==1) cout<<"West ";
else if(i==2) cout<<"North ";
else cout<<"East ";
cout<<"player:"<<endl;
for(k=0;k<13;k++)
cout<<"+---";
cout<<"+"<<endl;
for(j=12;j>=0;j--)
cout<<"|"<<a[i][j].y<<" "<<a[i][j].y;
cout<<"|"<<endl;
for(j=12;j>=0;j--)
cout<<"| "<<a[i][j].x<<" ";
cout<<"|"<<endl;
for(j=12;j>=0;j--)
cout<<"|"<<a[i][j].y<<" "<<a[i][j].y;
cout<<"|"<<endl;
for(int k=0;k<13;k++)
cout<<"+---";
cout<<"+"<<endl;
}
printf("\n");
getchar();
scanf("%c",&c);
getchar();
}
return 0;
}