WEEK2周记 A题———模拟类
一、题意
-
1.简述
假设如上图,这个烷烃基有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
是同一种,本质上就是一条链,编号其实是没有关系的,可以在纸上画画就懂了。 -
2.输入格式
输入第一行:数据的组数T(1≤T≤200000)。每组数据有5行,每行是两个整数a, b(1≤a,b≤6,a ≤b)。数据保证,输入的烷烃基是以上5种之一。 -
3.输出格式
每组数据,输出一行,代表烷烃基的英文名。 -
4.样例
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
二、算法
-
1.分析
分析图片中给出的五个同分异构体,不难看出每个节点(原子)的__度数__(这里采用了图论的说法)可以较好地区分这5个同分异构体。具体情况见如下表格:
分子类型 4度原子个数 3度原子个数 2度原子 个数 1度原子个数 n-hexane 0 0 4 2 2-methylpentane 0 1 2 3 3-methylpentane 0 1 2 3 2,3-dimethylbutane 0 2 0 4 2,2-dimethylbutane 1 0 1 4 由表格不难看出,除了2-methylpentane和 3-methylpentane这两种分子类型无法辨别出以外,其他的都可以通过该表轻松分辨。对于2-methylpentane和 3-methylpentane这两种分子类型,前者的2个2度原子连在一起,后者却没有(当然其他的辨别方法也是可以的)。
-
2.主要步骤
主要用到了三个数组来存储相关信息:
int c[7][7];//若两个原子之间有连线,则为1,否则为0 int num[7];//存储该分子的各个原子的度数 int cou[5];//存储该分子每种度数的原子个数
对于输入的每一组:
for(int j=0;j<5;j++) {//一边输入,一边更新c的数据和num的数据 int a,b; cin>>a>>b; c[a][b]=1; c[b][a]=1; num[a]++;num[b]++; }
利用num数组更新cou数组:
for(j=1;j<=6;j++) cou[num[j]]++;
利用if-else针对每种情况输出:
//4度原子只有一个: if(cou[4]==1) cout<<"2,2-dimethylbutane"<<endl; //3度原子有2个: else if(cou[3]==2) cout<<"2,3-dimethylbutane"<<endl; //2度原子有4个: else if(cou[2]==4) cout<<"n-hexane"<<endl;
对于2-methylpentane和 3-methylpentane这两种分子类型:
else { //找出两个2度原子的编号 int l=0,r=0; for(j=1;j<=6;j++) { if(num[j]==2) { if(!l) l=j; else r=j; } } if(c[l][r]==1) {//2度原子是相连的 cout<<"2-methylpentane"<<endl; } else {//2度原子并不连的 cout<<"3-methylpentane"<<endl; } }
需要注意的是,对于每一组都需要事先初始化清空为0,可以用memset函数。
-
3.测试结果
三、总结与收获
-
取消cin、cout与stdio之间的同步:
std::ios::sync_with_stdio(false);
但需要注意的是,取消同步之后似乎就不能用stdio里的scanf/printf/getchar……
出于尝试的目的这次只用了cin/cout来写,感觉上不如scanf/printf好用,遇到要求输出特殊的格式还是后者方便一些。
查阅到的一些相关方面的博客:
关于std::ios::sync_with_stdio(false);
关于C++中ios::sync_with_stdio(false); -
清空数组或初始化为0:
#include<cstring> memset(c,0,sizeof(c)); memset(num,0,sizeof(num)); memset(cou,0,sizeof(cou));
memset函数在string.h头文件中,对给定的区域按字节进行赋值,所以要是
memset(c,2,sizeof(c))
如果c数组的每一个元素都是int型,那么每一个元素并不会被赋值为2,相反是一个比较大的数;但是如果对每一个字节都赋值为0或者-1,那么对于每一个int的变量也都是0或-1。此外,还经常用memset(c,63,sizeof(c))
来将变量赋值为无穷大(因为复制完之后值比较大,接近int的最高上限)。
四、代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>//为了memset
using namespace std;
#define __ std::ios::sync_with_stdio(false)
int c[7][7];
int num[7];
int cou[5];
int main()
{
__;
int T,i,j;
cin>>T;
for(i=0;i<T;i++)
{
memset(c,0,sizeof(c));
memset(num,0,sizeof(num));
memset(cou,0,sizeof(cou));
for(j=0;j<5;j++)
{
int a,b;
cin>>a>>b;
c[a][b]=1;
c[b][a]=1;
num[a]++;num[b]++;
}
for(j=1;j<=6;j++)
{
cou[num[j]]++;
}
if(cou[4]==1)
{
cout<<"2,2-dimethylbutane"<<endl;
}
else if(cou[3]==2)
{
cout<<"2,3-dimethylbutane"<<endl;
}
else if(cou[2]==4)
{
cout<<"n-hexane"<<endl;
}
else
{
int l=0,r=0;
for(j=1;j<=6;j++)
{
if(num[j]==2)
{
if(!l)
l=j;
else
r=j;
}
}
if(c[l][r]==1)
{
cout<<"2-methylpentane"<<endl;
}
else
{
cout<<"3-methylpentane"<<endl;
}
}
}
return 0;
}