程序设计思维与实践 Week2 实验

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
是同一种,本质上就是一条链,编号其实是没有关系的,可以在纸上画画就懂了
Input
输入第一行为数据的组数T(1≤T≤200000)。每组数据有5行,每行是两个整数a, b(1≤a,b≤6,a ≤b)数据保证,输入的烷烃基是以上5种之一
Output
每组数据,输出一行,代表烷烃基的英文名
example Input
2
1 2
2 3
3 4
4 5
5 6
1 4
2 3
3 4
4 5
5 6
example Output
2
1 2
2 3
3 4
4 5
5 6
1 4
2 3
3 4
4 5
5 6
思路
将各个烷烃基看作是有六个顶点、五条边的无向图,用一个二维数组存储。
因为要区分这五个烷烃基,因此首先观察这五个烷烃基的不同之处。
据观察可知:

烷烃基特点
n-hexane度数为1的顶点:2个;度数为2的顶点:4个
2-methylpentane度数为1的顶点:3个;度数为2的顶点:2个;度数为3的顶点:1个;且度数为3的顶点连接有2个度数为1的顶点
3-methylpentane度数为1的顶点:3个;度数为2的顶点:2个;度数为3的顶点:1个;且度数为3的顶点连接有1个度数为1的顶点
2,3-dimethylbutane度数为1的顶点:4个;度数为3的顶点:2个
2,2-dimethylbutane度数为1的顶点:4个;度数为2的顶点:2个;度数为3的顶点:1个

可以设定一维数组c用来对应统计度数为i的顶点的个数;用sum来标记各个顶点的度数。根据上述表格发现的特点,进行判断烷烃基类别。

代码

#include<iostream>
using namespace std;

void change(int a[7][7])
{
	int sum[7] = { 0 };//统计顶点度数
	int c[7] = { 0 };//记录顶点度数为i的顶点个数
	for (int i = 1; i < 7; i++)
	{
		for (int j = 1; j < 7; j++)
		{
			if (a[i][j] == 1)
			{
				sum[i]++;
			}
		}
		c[sum[i]]++;
		if (sum[i] == 3)
		{
			c[0] = i;//记录度数为3的顶点,以便于区分2-methylpentane和3-methylpentane
		}
		
	}

	if (c[1] == 2 && c[2] == 4 && c[3] == 0 && c[4] == 0 && c[5] == 0)
	{
		cout << "n-hexane" << endl;
	}
	
	if (c[1] == 3 && c[2] == 2 && c[3] == 1 && c[4] == 0 && c[5] == 0)
	{
		int flag = 0;
		for (int i = 1; i < 7; i++)
		{
			if (sum[i] == 1)
			{
				if (a[c[0]][i] == 1)
				{
					flag++;//统计度数为3的顶点邻接的度数为1的顶点的个数
				}
			}
		}
		if (flag == 1)
		{
			cout << "3-methylpentane" << endl;
		}
		else
		{
			cout << "2-methylpentane" << endl;
		}

	}
	if (c[1] == 4 && c[2] == 1 && c[3] == 0 && c[4] == 1 && c[5] == 0)
	{
		cout << "2,2-dimethylbutane" << endl;
	}
	if (c[1] == 4 && c[2] == 0 && c[3] == 2 && c[4] == 0 && c[5] == 0)
	{
		cout << "2,3-dimethylbutane" << endl;
	}
}


int main()
{
	int n;
	cin >> n;
	
	for (int i = 0; i < n; i++)
	{
		int a[7][7] = { 0 };
		for (int j = 0; j < 5; j++)
		{
			int b, c;
			cin >> b >> c;
			a[b][c] = 1;
			a[c][b] = 1;
		}
		
		change(a);

	}

		
}

B-爆零(×)大力出奇迹(√)

程序设计思维作业和实验使用的实时评测系统,具有及时获得成绩排名的特点,那它的功能是怎么实现的呢?
我们千辛万苦怼完了不忍直视的程序并提交以后,评测系统要么返回AC,要么是返回各种其他的错误,不论是怎样的错法,它总会给你记上一笔,表明你曾经在这儿被坑过,而当你历经千辛终将它AC之后,它便会和你算笔总账,表明这题共错误提交了几次。
在岁月的长河中,你通过的题数虽然越来越多,但通过每题时你所共花去的时间(从最开始算起,直至通过题目时的这段时间)都会被记录下来,作为你曾经奋斗的痕迹。特别的,对于你通过的题目,你曾经的关于这题的每次错误提交都会被算上一定的单位时间罚时,这样一来,你在做出的题数上,可能领先别人很多,但是在做出同样题数的人中,你可能会因为罚时过高而处于排名上的劣势。
例如某次考试一共八道题(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个字符宽,右对齐)。名字、题数和时间分相互之间有一个空格。数据保证可按要求的输出格式进行输出。
Sample Input
8 20
GuGuDong 96 -3 40(3) 0 0 1 -8 0
hrz 107 67 -3 0 0 82 0 0
TT 120(3) 30 10(1) -3 0 47 21(2) -2
OMRailgun 0 -99 -8 0 -666 -10086 0 -9999996
yjq -2 37(2) 13 -1 0 113(2) 79(1) -1
Zjm 0 0 57(5) 0 0 99(3) -7 0
Sample Output
TT 5 348
yjq 4 342
GuGuDong 3 197
hrz 3 256
Zjm 2 316
OMRailgun 0 0
思路
由题意可知,只有当一道题AC之后才会出现罚时,一道题目AC则表示改题目有正数得分。
据此可以利用sscanf()来按照%d(%d)标准的读取每一道题的得分情况。
如果读出来的是一个数,并且该数大于零则说明该题目AC,由于没有括号里面的数,说明改题目一遍通过,该题的罚时为读出的数(即做该题所需要的时间);
如果读出来的是两个数,则改题目AC,且该题的罚时时间为第一个数+第二个数×单位罚时(即做该题需要的时间+错误提交的罚时)。
据此统计信息进行排序。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>

using namespace std;

struct student
{
	char name[20];//名字
	int AC;//AC题目数量
	int tpenalty;//罚时
};


bool cmp(student &ra,student& rv)//排序规则
{
	if (ra.AC != rv.AC)return ra.AC > rv.AC;
	if (ra.tpenalty != rv.tpenalty)return ra.tpenalty < rv.tpenalty;
	return strcmp(ra.name, rv.name) < 0;
}


int main()
{
	int n, m;
	student s[1000];
	cin >> n >> m;
	int i;
	for (i = 0; scanf("%10s", s[i].name) != EOF; i++)
	{
		s[i].AC = 0;
		s[i].tpenalty = 0;
		for (int j = 0; j < n; j++)
		{
			char mark[20] = { 0 };
			scanf("%s", mark);
			int first, second;
			int result = sscanf(mark, "%d(%d)", &first, &second);
			if (result == 2)
			{
				s[i].AC++;
				s[i].tpenalty = s[i].tpenalty + first + second * m;
			}
			else if (result == 1 && first > 0)
			{
				s[i].AC++;
				s[i].tpenalty += first;
			}
		}
	}
	sort(s, s + i, cmp);
	for (int j = 0; j < i; j++)
	{
		printf("%-10s %2d %4d\n", s[j].name, s[j].AC, s[j].tpenalty);
	}
	

}

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的结果,每位玩家先输出一行即玩家名称(东南西北),接下来五行,第一行和第五行输出固定格式(见样例),第二行和第四行按顺序和格式输出数值(见样例),第三行按顺序和格式输出花色(见样例)。
Sample Input
N
CTCAH8CJD4C6D9SQC7S5HAD2HJH9CKD3H6D6D7H3HQH4C5DKHKS9
SJDTS3S7S4C4CQHTSAH2D8DJSTSKS2H5D5DQDAH7C9S8C8S6C2C3

Sample Output
South player:
±–±--±–±--±–±--±–±--±–±--±–±--±–+
|6 6|A A|6 6|J J|5 5|6 6|7 7|9 9|4 4|5 5|7 7|9 9|T T|
| C | C | D | D | S | S | S | S | H | H | H | H | H |
|6 6|A A|6 6|J J|5 5|6 6|7 7|9 9|4 4|5 5|7 7|9 9|T T|
±–±--±–±--±–±--±–±--±–±--±–±--±–+
West player:
±–±--±–±--±–±--±–±--±–±--±–±--±–+
|2 2|5 5|9 9|K K|5 5|7 7|9 9|4 4|T T|J J|A A|8 8|A A|
| C | C | C | C | D | D | D | S | S | S | S | H | H |
|2 2|5 5|9 9|K K|5 5|7 7|9 9|4 4|T T|J J|A A|8 8|A A|
±–±--±–±--±–±--±–±--±–±--±–±--±–+
North player:
±–±--±–±--±–±--±–±--±–±--±–±--±–+
|3 3|4 4|J J|2 2|3 3|T T|Q Q|K K|8 8|Q Q|K K|2 2|3 3|
| C | C | C | D | D | D | D | D | S | S | S | H | H |
|3 3|4 4|J J|2 2|3 3|T T|Q Q|K K|8 8|Q Q|K K|2 2|3 3|
±–±--±–±--±–±--±–±--±–±--±–±--±–+
East player:
±–±--±–±--±–±--±–±--±–±--±–±--±–+
|7 7|8 8|T T|Q Q|4 4|8 8|A A|2 2|3 3|6 6|J J|Q Q|K K|
| C | C | C | C | D | D | D | S | S | H | H | H | H |
|7 7|8 8|T T|Q Q|4 4|8 8|A A|2 2|3 3|6 6|J J|Q Q|K K|
±–±--±–±--±–±--±–±--±–±--±–±--±–+
思路
每副牌输入的是两个字符串str1,str2,每个字符串52个字符,即代表26张牌,统一发牌后,四个人每个人都有13张牌。因此构造牌结构体,定义四个结构体数组用来存储四个人应该拥有的牌。
因为是按顺序发送,所以每发一轮要遍历8个字符,可以根据字符所在的位置(即str1[i]或者是str2[i])对8的余数来判断该字符是属于按顺序发牌时的第几个人,并判断该字符是牌面数值还是花色,由此进行存储。
将所有的牌都分配完成后,按照花色和牌面大小进行排序,并按照发牌人所在的位置进行顺序输出。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
using namespace std;

struct cards
{
	char decor;//花色
	char number;//牌面大小

};

int map1(char a)//花色大小赋值
{
	if (a == 'C')return 0;
	if (a == 'D')return 1;
	if (a == 'S')return 2;
	if (a == 'H')return 3;
}

int map2(char a)//牌面大小赋值
{
	if (a == '2')return 2;
	if (a == '3')return 3;
	if (a == '4')return 4;
	if (a == '5')return 5;
	if (a == '6')return 6;
	if (a == '7')return 7;
	if (a == '8')return 8;
	if (a == '9')return 9;
	if (a == 'T')return 10;
	if (a == 'J')return 11;
	if (a == 'Q')return 12;
	if (a == 'K')return 13; 
	if (a == 'A')return 14;
	
}


bool cmp(cards& a, cards& b)//比较大小
{
	if (a.decor != b.decor)return map1(a.decor) < map1(b.decor);
	else return map2(a.number) < map2(b.number);
}



void output(cards f[14])
{
	sort(f, f + 13, cmp);//排序

	cout << "+---+---+---+---+---+---+---+---+---+---+---+---+---+" << endl;
	for (int i = 0; i < 13; i++)
	{
		cout << "|" << f[i].number << " " << f[i].number;
	}
	cout << "|" << endl;
	for (int i = 0; i < 13; i++)
	{
		cout << "| " << f[i].decor << " ";
	}
	cout << "|" << endl;
	for (int i = 0; i < 13; i++)
	{
		cout << "|" << f[i].number << " " << f[i].number;
	}
	cout << "|" << endl;
	cout << "+---+---+---+---+---+---+---+---+---+---+---+---+---+" << endl;
}






void dealer(char &first,string &str1,string &str2)//发牌
{
	cards f[14];
	cards s[14];
	cards t[14];
	cards fo[14];
	int j = 0;
	for (int i = 0; i < (int)str1.size(); i++)
	{
		if (i % 8 == 0)f[j].decor = str1[i];
		if (i % 8 == 1)f[j].number = str1[i];
		if (i % 8 == 2)s[j].decor = str1[i];
		if (i % 8 == 3)s[j].number = str1[i];
		if (i % 8 == 4)t[j].decor = str1[i];
		if (i % 8 == 5)t[j].number = str1[i];
		if (i % 8 == 6)fo[j].decor = str1[i];
		if (i % 8 == 7)fo[j++].number = str1[i];
		
	}
	for (int i = 0; i < (int)str2.size(); i++)
	{
		if (i % 8 == 0)t[j].decor = str2[i];
		if (i % 8 == 1)t[j].number = str2[i];
		if (i % 8 == 2)fo[j].decor = str2[i];
		if (i % 8 == 3)fo[j++].number = str2[i];
		if (i % 8 == 4)f[j].decor = str2[i];
		if (i % 8 == 5)f[j].number = str2[i];
		if (i % 8 == 6)s[j].decor = str2[i];
		if (i % 8 == 7)s[j].number = str2[i];
		
	}
	if (first == 'N')
	{
		cout << "South player:" << endl;
		output(s);
		cout << "West player:" << endl;
		output(t);
		cout << "North player:" << endl;
		output(fo);
		cout << "East player:" << endl;
		output(f);
	}
	if (first == 'S')
	{
		cout << "South player:" << endl;
		output(fo);
		cout << "West player:" << endl;
		output(f);
		cout << "North player:" << endl;
		output(s);
		cout << "East player:" << endl;
		output(t);
	}
	if (first == 'W')
	{
		cout << "South player:" << endl;
		output(t);
		cout << "West player:" << endl;
		output(fo);
		cout << "North player:" << endl;
		output(f);
		cout << "East player:" << endl;
		output(s);
	}
	if (first == 'E')
	{
		cout << "South player:" << endl;
		output(f);
		cout << "West player:" << endl;
		output(s);
		cout << "North player:" << endl;
		output(t);
		cout << "East player:" << endl;
		output(fo);
	}


}



int main()
{
	char first;
	string str1;
	string str2;
	while (1)
	{
		cin >> first;
		if (first == '#')
		{
			break;
		}
		cin >> str1 >> str2;
		dealer(first, str1, str2);
		cout << endl;
	}

}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值