题目A
题目描述
假设如上图,这个烷烃基有6个原子和5个化学键,6个原子分别标号1~6,然后用一对数字 a,b 表示原子a和原子b间有一个化学键。这样通过5行a,b可以描述一个烷烃基
你的任务是甄别烷烃基的类别。
原子没有编号方法,比如
1 2
2 3
3 4
4 5
5 6
和
1 3
2 3
2 4
4 5
5 6
是同一种,本质上就是一条链,编号其实是没有关系的
输入
输入第一行为数据的组数T(1≤T≤200000)。每组数据有5行,每行是两个整数a, b(1≤a,b≤6,a ≤b)
数据保证,输入的烷烃基是以上5种之一
输出
每组数据,输出一行,代表烷烃基的英文名
问题理解
我们来仔细的分析图片,你会发现这五个烷烃其实就是以前所学习的同分异构体。顶点的个数都是一样的,只是构造不一样。这个时候就需要从构造上来区分他们的不同。
1.首先我建立了一个结构体chemical_bond,用来存放它的入度以及和它相连接的顶点的名称。
2.然后我建立了一个类alkyl,用来专门对输入的烷烃处理,包含初始化、建立连接和输出。其中jisuan这个变量用来储存整个烷烃中顶点的最大的度的情况(这里我做了一些改变,导致意义差不多,但其值却不是最大的度,主要流程就是每次遇见度为3,4的点就使jisuan的值增加1,2)。thealkyl是以结构体chemical_bond为基础的线性表,用来储存每个节点的链接情况。
3.每一次输入两个顶点,就采用connected函数将其输入进类的线性表中。并对那两个顶点的度进行计算。它们所链接的点也加入其结构体里的shu[]中;
4.判断是什么烷烃时,首先检查我们之前处理的jisuan的值。由图可知分别是:0,1,1,2,3;依靠这个举动可以判断出其中的三类情况。剩下两个最大入度为3的,我采用遍历其顶点,找到最大入度的顶点,再观察它的所邻着的点的入度。三个邻点有两个是入度为2的是3-methylpentane,剩下的就是2-methylpentane。即可完成判断。
代码样例
#include<iostream>
#include<cmath>
//#include<queue>
//n-hexane,2-methylpentane,3-methylpentane,2,3-dimethlbutane,2,2-dimethylbutane;
using namespace std;
struct chemical_bond
{
int du;
int shu[6];
} ;
template<class T>
class alkyl
{
public:
alkyl()
{
thealkyl=new struct chemical_bond [7];
jisuan=0;
for(int i=1;i<=6;i++)
{
thealkyl[i].du=0;
}
}
void clear()//初始化
{
jisuan=0;
for(int i=1;i<=6;i++)
{
thealkyl[i].du=0;
}
}
void connected(int a,int b);
void output();
private:
struct chemical_bond *thealkyl;
int jisuan;
};
template<class T>
void alkyl<T>::connected(int a,int b)
{
thealkyl[a].shu[thealkyl[a].du]=b;
thealkyl[b].shu[thealkyl[b].du]=a;
thealkyl[a].du++;
thealkyl[b].du++;
if(thealkyl[a].du>3)
jisuan=jisuan+2;
else if(thealkyl[a].du>2)
jisuan++;
if(thealkyl[b].du>3)
jisuan=jisuan+2;
else if(thealkyl[b].du>2)
jisuan++;
}
template<class T>
void alkyl<T>::output()
{
if(jisuan==3)
{
//cout<<jisuan<<endl;
cout<<"2,2-dimethylbutane"<<endl;
jisuan=0;
return;
}
if(jisuan==2)
{
// cout<<jisuan<<endl;
cout<<"2,3-dimethylbutane"<<endl;
jisuan=0;
return;
}
if(jisuan==0)
{
//cout<<jisuan<<endl;
cout<<"n-hexane"<<endl;
jisuan=0;
return;
}
if(jisuan==1)
{
// cout<<jisuan<<endl;
int i;
for(i=0;i<6;i++)
{
if(thealkyl[i].du==3)
break;
}
int num=0;
for(int j=0;j<thealkyl[i].du;j++)
{
if(thealkyl[thealkyl[i].shu[j]].du==2)
num++;
}
if(num==2)
cout<<"3-methylpentane"<<endl;
else
cout<<"2-methylpentane"<<endl;
jisuan=0;
}
else
cout<<"计算wrong jisuan="<<jisuan<<endl;
return;
}
int main()
{
int N;
int a,b;
cin>>N;
alkyl<int> g;
for(int i=0;i<N;i++)
{
g.clear();
for(int j=0;j<5;j++)
{
cin>>a>>b;
g.connected(a,b);
}
g.output();
}
}
遇到的问题
代码有些累赘,对于stl的使用不多,并且在调试的过程中废了很多功夫,就是因为那些循环的变量没有处理到位
题目B——HDU2093排序
题目描述
程序设计思维作业和实验使用的实时评测系统,具有及时获得成绩排名的特点,那它的功能是怎么实现的呢?
我们千辛万苦怼完了不忍直视的程序并提交以后,评测系统要么返回AC,要么是返回各种其他的错误,不论是怎样的错法,它总会给你记上一笔,表明你曾经在这儿被坑过,而当你历经千辛终将它AC之后,它便会和你算笔总账,表明这题共错误提交了几次。
在岁月的长河中,你通过的题数虽然越来越多,但通过每题时你所共花去的时间(从最开始算起,直至通过题目时的这段时间)都会被记录下来,作为你曾经奋斗的痕迹。特别的,对于你通过的题目,你曾经的关于这题的每次错误提交都会被算上一定的单位时间罚时,这样一来,你在做出的题数上,可能领先别人很多,但是在做出同样题数的人中,你可能会因为罚时过高而处于排名上的劣势。
例如某次考试一共八道题(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个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。数据保证可按要求的输出格式进行输出。
问题理解
1.首先定义了一个结构体 person,包含参赛者的姓名char、对的题数int、用时int。
2.再建立一个线性表person_grade[],用以储存所有的参赛者的情况
3.输入时,直接输入参赛者姓名,再输入一个数字。根据和这个数字的大小来判断是否会有字符在里面。因为输入的格式只有,正数、正数(正整数),负数,零这几个情况。于是只要输入的数大于零,就判断是否会时‘正数(正整数)’的情况。
并在输入的时候,对每次的时间并加上其罚时直接处理好。
4.比较,采用了sort函数,头文件algorithm。用法sort(first_pointer,first_pointer+n,cmp);其中cmp是自己定义的bool函数,用来比较大小。(为了便于理解,即bool compared(a,b)中,a是前一个元素,b是后一个元素。整个sort函数就是改变排序,使得其compared(a,b)回值为真的的排列情况即可。这个方法大大减少了我码代码要求。
5.输出,这个输出是看网上的代码。%-10s 其意思就是把name的字符串从0到9全部输出,%2d和%4d就是输出几位的整数。
代码
#include <iostream>
#include <algorithm>
using namespace std;
struct person
{
char name[10];
int number;
int time;
};
bool compare(person& a,person& b)
{
if(a.number!=b.number)
{
return a.number>b.number;
}
else
{
if(a.time!=b.time)
{
return a.time<b.time;
}
else
{
return a.name> b.name;
}
}
}
int main()
{
int i=0;
int n,m;
cin>>n>>m;
int shu,a;
struct person person_grade[10000];
while(cin>>person_grade[i].name)
{
person_grade[i].number=0;
person_grade[i].time=0;
for(int j=0;j<n;j++)
{
cin>>shu;
if(shu>0)
{
person_grade[i].number++;
person_grade[i].time=person_grade[i].time+shu;
if(getchar()=='(')
{
cin>>a;
person_grade[i].time=person_grade[i].time+a*m;
getchar();//吸收另一个括号
}
}
}
i++;
}
sort(person_grade,person_grade+i,compare);
int k;
for(k=0;k<i;k++){
printf("%-10s %2d %4d\n",person_grade[k].name,person_grade[k].number,person_grade[k].time);
}
}
问题
对于stl不太熟,是看了网上的代码改编的,不过,这样也让我了解了这个用法,不错。
问题C——POJ1786
问题描述
牌局由四个人构成,围成一圈。我们称四个方向为北 东 南 西。对应的英文是North,East,South,West。游戏一共由一副扑克,也就是52张构成。开始,我们指定一位发牌员(东南西北中的一个,用英文首字母标识)开始发牌,发牌顺序为顺时针,发牌员第一个不发自己,而是发他的下一个人(顺时针的下一个人)。这样,每个人都会拿到13张牌。
现在我们定义牌的顺序,首先,花色是(梅花)<(方片)<(黑桃)<(红桃),(输入时,我们用C,D,S,H分别表示梅花,方片,黑桃,红桃,即其单词首字母)。对于牌面的值,我们规定2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < T < J < Q < K < A。
现在你作为上帝,你要从小到大排序每个人手中的牌,并按照给定格式输出。(具体格式见输出描述和样例输出)。
输入
输入包含多组数据
每组数据的第一行包含一个大写字符,表示发牌员是谁。如果该字符为‘#’则表示输入结束。
接下来有两行,每行有52个字符,表示了26张牌,两行加起来一共52张牌。每张牌都由两个字符组成,第一个字符表示花色,第二个字符表示数值。
输出
输出多组数据发牌的结果,每组数据之后需要额外多输出一个空行!!!!!
每组数据应该由24行的组成,输出按照顺时针方向,始终先输出South Player的结果,每位玩家先输出一行即玩家名称(东南西北),接下来五行,第一行和第五行输出固定格式(见样例),第二行和第四行按顺序和格式输出数值(见样例),第三行按顺序和格式输出花色(见样例)。
问题分析
1.建立了一个结构体card,包含其牌面number,牌的花色color。
2.采用二维线性表playing_card来存放输入的发牌顺序,其中先对哪一个玩家发牌做一个处理。我直接是一个个比较一开始输入的字符。并对k进行赋值。这样在输入的循环里就可以从k到k+n进行来回对二维线性表输入。
3.排序时,我采用了sort函数和map函数。对每一个玩家手上的牌用sort函数进行排序。为了方便排序,建立了一个map color_compared。并在主函数里对每个花色赋予对应的优先值。(按照其比较的顺序来)
4.对应着输出即可
代码
#include<iostream>
using namespace std;
#include<algorithm>
#include<map>
struct card
{
char number;
char color;
};
//2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < T < J < Q < K < A。 ;;;
//C,D,S,H
//S,W,N,E
map<char,int> color_compared;
bool compared(card& a,card& b)
{
if(a.color!=b.color)
{
return color_compared[a.color]<color_compared[b.color];
}
else
{
return color_compared[a.number]<color_compared[b.number];
}
}
int main()
{
color_compared['2']=1;
color_compared['3']=2;
color_compared['4']=3;
color_compared['5']=4;
color_compared['6']=5;
color_compared['7']=6;
color_compared['8']=7;
color_compared['9']=8;
color_compared['T']=9;
color_compared['J']=10;
color_compared['Q']=11;
color_compared['K']=12;
color_compared['A']=13;
color_compared['C']=1;
color_compared['D']=2;
color_compared['S']=3;
color_compared['H']=4;
char player;
scanf("%c",&player);
while(player!='#')
{
struct card playing_card[4][13];
int k;
if(player=='S')
k=1;
if(player=='W')
k=2;
if(player=='N')
k=3;
if(player=='E')
k=0;
//cout<<k<<" "<<player<<endl;
getchar();
for(int i=0;i<13;i++)
{
for(int j=k;j<k+4;j++)
{
if(i==6&&j==k+2)
getchar();
scanf("%c",&playing_card[j%4][i].color);
scanf("%c",&playing_card[j%4][i].number);
//cout<< playing_card[j%4][i].color<<" "<<playing_card[j%4][i].number<<endl;
}
}
sort(playing_card[0],playing_card[0]+13,compared);
sort(playing_card[1],playing_card[1]+13,compared);
sort(playing_card[2],playing_card[2]+13,compared);
sort(playing_card[3],playing_card[3]+13,compared);
for(int i=0;i<4;i++)
{
if(i==0)
cout<<"South player:"<<endl;
if(i==1)
cout<<"West player:"<<endl;
if(i==2)
cout<<"North player:"<<endl;
if(i==3)
cout<<"East player:"<<endl;
cout<<"+---+---+---+---+---+---+---+---+---+---+---+---+---+"<<endl;
cout<<"|";
for(int j=0;j<13;j++)
{
cout<<playing_card[i][j].number<<" "<<playing_card[i][j].number<<"|";
}
cout<<endl;
cout<<"|";
for(int j=0;j<13;j++)
{
cout<<" "<<playing_card[i][j].color<<" "<<"|";
}
cout<<endl;
cout<<"|";
for(int j=0;j<13;j++)
{
cout<<playing_card[i][j].number<<" "<<playing_card[i][j].number<<"|";
}
cout<<endl;
cout<<"+---+---+---+---+---+---+---+---+---+---+---+---+---+"<<endl;
}
cout<<endl;
getchar();
scanf("%c",&player);
}
}
遇到的问题
1.输入时莫名其妙对的不准,我做了调试之后发现,是输入时里面有回车,但是把它当作一个字符读进去了,导致后面的对不上,全部错位。于是在里面加了两个getchar来吸收回车。
2.读题时,没读准,理所应当的按照自己的习惯排了序,结果出来,才发现要求是先花色再大小。