第二周实验-化学

独自空忆成欢 提交于 2020-03-06 10:00:37

题目描述:化学很神奇,以下是烷烃基。

在这里插入图片描述
假设如上图,这个烷烃基有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种之一
输出:
每组数据,输出一行,代表烷烃基的英文名
sample:
Input
2
1 2
2 3
3 4
4 5
5 6
1 4
2 3
3 4
4 5
5 6
Output
n-hexane
3-methylpentane
题目思路:
本题的思路就是找到这五种烷烃的规律,首先题目中说明了原子编号没有固定的方法,这样我们只能看原子与化学键之间的数量关系,那么观察可以看到,n-hexane所有的化学键只能连接两个原子,2,3-dimethylbutane有两个原子连接三个化学键,2,2-dimethylbutane有一个原子连接四个化学键,对于这三种烷烃比较容易求得,也就是用一个一维数组记录下来每个原子连接的化学键个数,分为没有3、有两个3、有一个4三种情况。
但是剩余两种他们都有一个原子连接三个化学键,这样我们发现,3-methylpentane中连接三个化学键的原子周围的原子有两个是连接两个化学键的,而2-methylpentane中连接三个化学键的原子周围的原子有一个是连接两个化学键的,所以我们可以用矩阵表示成无向图,记录下每一条边(输入的时候是一条边,编程的时候把对称的点对加进去),遍历每个点找到哪个点有三条边(主题题目里提到原子没有编号方法,所以每一个原子都有可能是,所以只能扫描一遍确认),找到这个点之后记录下三条边对应的三个点,再遍历这三个点,找找他们周围有几条边,分为两个点有两条边、一个点有两条边两种情况。
代码如下:

#include<iostream>
using namespace std;
int main()
{
	int t;
	int aa[3]={0,0,0};//记录一个有三条临边的点周围的三个点	
	cin>>t;
	for(int i=1;i<=t;i++)
	{
		int count1=0;//记录下有三条临边的点的个数
     	int count2=0;//记录下有四条临边的点的个数
		int s[7]={0,0,0,0,0,0,0};//记录下每个点有多少临边
		int ss[7][7]=//把输入的边用无向图记录下来
		{
			{0,0,0,0,0,0,0},
			{0,0,0,0,0,0,0},
			{0,0,0,0,0,0,0},
			{0,0,0,0,0,0,0},
			{0,0,0,0,0,0,0},
			{0,0,0,0,0,0,0},
			{0,0,0,0,0,0,0}
		};
		int a,b;
		for(int j=1;j<=5;j++)
		{
			cin>>a>>b;
			s[a]++;//由于是无向图,那么两个点都应该算一次
			s[b]++;
			ss[a][b]++;//记录下边,同时由于无向图反过来再记录一次
			ss[b][a]++;	
		}
		for(int k=1;k<=6;k++)
		{
			if(s[k]==3)
			count1++;
			if(s[k]==4)
			count2++;
		}
		if(count1==0&&count2==0)//没有点有三条和四条临边
		{
			cout<<"n-hexane"<<endl;
		}
		else if(count1==2)//有两个点有三条临边
		{
			cout<<"2,3-dimethylbutane"<<endl;
		}
		else if(count2==1)//有一个点有四条临边
		{
			cout<<"2,2-dimethylbutane"<<endl;
		}
		else
		{
			for(int j=1;j<=6;j++)
			{
				int count3=0;//记录下有三条临边的点的个数
				for(int k=1;k<=6;k++)
				{
					if(ss[j][k]==1)//有这条边就加入到数组a中
					{
						aa[count3]=k;//如果这一遍循环数组a不满没关系,下一次由于count3清零,会重新覆盖掉数组a,直到数组a满足有三个点为止
						count3++;
					}
					if(count3==3)//双重循环是不能直接break的,需要强制让内层外层都满足循环条件才能退出
					{
						j=6;
						k=6;
					}
				}
			}
			int count5=0;//记录有三条临边的点周围的三个点有两条临边的个数
			for(int k=0;k<=2;k++)
			{
			    int count4=0;//记录相邻的点临边的个数
				for(int j=1;j<=6;j++)
			    {
				    if(ss[j][aa[k]]==1)//有这条边那就成立
				    count4++;
			    }
			    if(count4==2)
				count5++;
			}
			if(count5==2)//有三条临边的点周围的点有两条临边的个数为2
			cout<<"3-methylpentane"<<endl;
			if(count5==1)//有三条临边的点周围的点有两条临边的个数为1
			cout<<"2-methylpentane"<<endl;
		}
	}
	return 0;
}

运行结果:
在这里插入图片描述

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!