SDU week2 (A 化学 B爆零大力出奇迹 C 瑞神打牌)

【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;
}
发布了10 篇原创文章 · 获赞 0 · 访问量 173

猜你喜欢

转载自blog.csdn.net/weixin_45736432/article/details/104643869
今日推荐