A - 化学
题意
己烷,这个烷烃基有6个原子和5个化学键,因此有五种结构(如上图所示),即n-hexane、2-methylpentane、3-methylpentane、2,3-dimethylbutane、2,2-dimethylbutane这五种。为了区分这五种结构,我们将这6个原子分别标号1~6,然后用一对数字 a,b 表示原子a和原子b间有一个化学键。这样通过5行a,b就可以描述一个烷烃基,而我们要做的就是通过这5行数据找到相对应的烷烃基。
思路
通过观察我们可以发现,上述五种结构中连接其他另外两个碳原子的碳原子数量分别为4,2,2,0,1。因此我们通过统计这类碳原子的数目就可区分出己烷,2,3-二甲基丁烷和2,2-二甲基丁烷,而2-甲基丁烷和3-甲基丁烷则无法通过这种方式进行区分,因此需要对这两种结构进行额外的比较,通过观察发现虽然两者都有一个连接其他另外三个碳原子相连的碳原子,但2-甲基丁烷中这三个碳原子中有两个甲基,而3-甲基丁烷中这三个碳原子中只有一个甲基。因此通过统计这类甲基的数量即可区分两种结构。
代码
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
int f[6]; //用于存放相连接的碳原子,用于区分2-甲基丁烷和3-甲基丁烷
int main()
{
int a,b,n,num,x1,x2;
cin>>n;
int count[6];
while(n!=0)
{
for(int i=0;i<6;i++)
{
count[i]=0;
f[i]=0;
}
x1 = 0,x2 = 0,num = 0;
for(int i=0;i<5;i++)
{
cin>>a>>b;
count[a-1]++;
count[b-1]++;
f[a-1]=b-1;
f[b-1]=a-1;
}
for(int i=0;i<6;i++)
{
if(count[i]==2)
num++;
}
if(num == 0)
cout<<"2,3-dimethylbutane"<<endl;
if(num == 1)
cout<<"2,2-dimethylbutane"<<endl;
if(num == 2)
{
for(int i=0;i<6;i++)
if(count[i]==1)
{
x1 = f[i];
if(count[x1] == 3)
x2++;
}
if(x2==2)
cout<<"2-methylpentane"<<endl;
else
cout<<"3-methylpentane"<<endl;
}
if(num == 4)
cout<<"n-hexane"<<endl;
n--;
}
return 0;
}
B - 大力出奇迹
题意
目前正在进行一场程序设计实验,一共N到题每个人做的题都在对应的题号下有个数量标记,负数表示该学生在该题上有过的错误提交次数但到现在还没有AC,正数表示AC所耗的时间,如果正数a跟上了一对括号,里面有个正数b,则表示该学生AC了这道题,耗去了时间a,同时曾经错误提交了b次(错误提交会造成罚时)。然后我根据这些学生的答题现状,输出一个实时排名。实时排名先按AC题数的多少排,多的在前,再按时间分的多少排,少的在前,如果凑巧前两者都相等,则按名字的字典序排,小的在前。
思路
简单来说就是如题目所说,大力出奇迹,没有什么复杂的操作,就是根据每个题目下的答题情况得出每一道题目的用时(实际耗费时间+罚时)和通过情况,从而得到所有题目的通过个数和答题用时,从而给所有的同学进行排序,由于可能有"(“和”)"因此采用string类型,通过逐个读取字符来计算用时。
注意:
本题的难点可能主要在于输出格式上,在这里浪费了很长时间。
具体要求为每个学生占一行,输出名字(10个字符宽),做出的题数(2个字符宽,右对齐)和时间分(4个字符宽,右对齐)
printf("%d",a)默认为左对齐;
printf("%-10d",a)为左对齐,10代表数字宽度为10,如果要打印的位数小于10,则在后面补足空格;如果要打印的位数大于10,则打印所有的数字,不会截断;
printf("%10d",101010);
在%和d之间加上数字宽度,就可以右对齐,10与上面含义相同。
代码
#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string>
using namespace std;
struct cmp{
int x,y;
char name[10];
cmp(){}
bool operator <(const cmp&n){
if(x!=n.x)
return x>n.x;
if(x==n.x)
{
if(y!=n.y)
return y<n.y;
if (y==n.y)
return name>n.name;
}
}
};
int main()
{
int m,n;
cin>>m>>n;
cmp peo[1000];
int i=0, sum=0,num = 0;
string a;
while (scanf("%s",&peo[i].name)!=EOF)
{
for(int s=0;s<m;s++)
{
cin>>a;
if(a[0]=='-'||a[0]=='0')
continue;
peo[i].x++;
int j=0;
sum = 0,num = 0;
while(a[j]!='('&&a[j]!='\0')//统计实际用时和答对题目数
{
sum=sum*10+(a[j]-'0');
j++;
}
if(a[j]=='(') //计算罚时
{
j++;
while(a[j]!=')'&&a[j]!='\0')
{
num=num*10+(a[j]-'0');
j++;
}
}
peo[i].y+=sum+num*n;
}
i++;
}
sort(peo,peo+i);
for(int na=0;na<i;na++)
printf("%-10s %2d %4d\n",peo[na].name,peo[na].x,peo[na].y);
return 0;
}
C - 瑞神打牌
题意
四个人在打牌,一共有52张牌,目前我们已经知道牌序、发牌方式(顺时针发牌)及发牌起始位置,由此推算出四个人手中的13张牌分别是什么,并按指定方式进行排序,首先,先按花色排,花色是(梅花)<(方片)<(黑桃)<(红桃),(输入时,我们用C,D,S,H分别表示梅花,方片,黑桃,红桃,即其单词首字母);然后再按牌面的值排,我们规定2 < 3 < 4 < 5 < 6 < 7 < 8 < 9 < T < J < Q < K < A, 然后按指定格式输出。
思路
由于T,J,Q,K,A不便于进行比较,因此要将他们转换成数字,为了便于进行操作我们可以将四个人(E, W,S,N)和2-9都重新转换一下,由于本题不支持C++11进行map初始化时太过繁琐,故采用了数组返回值的方式进行。派牌和排序没有难度,就是最后的输出由于有特定的输出顺序,因此我们要根据发牌起始位置的不同来选择输出顺序。
具体如下:
若从S开始发牌,从头开始每13张输出即可;
若从W开始发牌,则应先输出最后13张,再从头输出;
若从N开始发牌,则应从第27张开始每13张输出;
若从E开始发牌,则应从第14张开始输出。
注意:由于花色黑桃和位于南面的人都用S表示,因此一定要注意两者之间的区别
代码
#include<iostream>
#include<stdio.h>
#include <string.h>
using namespace std;
string code="23456789TJQKACDSHSWNE#";//用于进行字母与数字的匹配
int convert(char s)//将输入的字符s转换成特定的数字
{
int i;
for(i=0;i<code.size();i++)
{
if(s==code[i])
return i;
}
return 0;
}
struct paper{
int a,b;
paper(){
}
bool operator <(const paper &x){ //重载<用于进行纸牌的排序
if(a!=x.a)
return a<x.a;
else
return b<x.b;
}
};
paper p1[52]; //牌堆中前26张牌的顺序
paper p2[52]; //牌堆中后26张牌的顺序
void print(int m){ //按特定格式输出
for(int i=m;i<m+13;i++)
cout<<"+---";
cout<<"+"<<endl;
for(int i=m;i<m+13;i++)
{
int s1=p2[i].a,s2=p2[i].b;
cout<<"|"<<code[s2]<<" "<<code[s2];
}
cout<<"|"<<endl;
for(int i=m;i<m+13;i++)
{
int s1=p2[i].a,s2=p2[i].b;
cout<<"| "<<code[s1]<<" ";
}
cout<<"|"<<endl;
for(int i=m;i<m+13;i++)
{
int s1=p2[i].a,s2=p2[i].b;
cout<<"|"<<code[s2]<<" "<<code[s2];
}
cout<<"|"<<endl;
for(int i=m;i<m+13;i++)
cout<<"+---";
cout<<"+"<<endl;
}
void sort(int m) //插入排序
{
paper temp;
for (int i = 13; i > 0; i--) { // 每次需要排序的长度
for (int j = m; j < m+12; j++) { // 从第一个元素到第i个元素
if (p2[j+1] <p2[j]) {
temp = p2[j];
p2[j] = p2[j + 1];
p2[j + 1] = temp;
}
}//loop j
}//loop i
}
int main(){
string m;;
while(cin>>m)
{
int now=convert(m[0]); //确定从谁开始排牌
if(now==21)
return 0;
string a,b;
cin>>a>>b; //分别输入前26张牌和后26张牌的顺序
int x1,x2;
for(int i=0,j=0;i<52;i=i+2,j++)
{
x1=convert(a[i]); //将花色转换成数字进行存储,便于进行比较
p1[j].a=x1;
x2=convert(a[i+1]); //将牌值转换成数字进行存储,便于进行比较
p1[j].b=x2;
}
for(int i=0,j=26;i<52;i=i+2,j++)
{
x1=convert(b[i]); //将花色转换成数字进行存储,便于进行比较
p1[j].a=x1;
x2=convert(b[i+1]); //将牌值转换成数字进行存储,便于进行比较
p1[j].b=x2;
}
now = now%17; //由now的值确定输出顺序
if(now>4)
now=0;
for(int i=0,j=0;i<52;i=i+4,j++)//完成发牌
{
p2[j]=p1[i];
p2[j+13]=p1[i+1];
p2[j+26]=p1[i+2];
p2[j+39]=p1[i+3];
}
sort(0); //对四个人的牌进行排序
sort(13);
sort(26);
sort(39);
cout<<"South player:"<<endl;
if(now == 3)
{
print(0);
cout<<"West player:"<<endl;
print(13);
cout<<"North player:"<<endl;
print(26);
cout<<"East player:"<<endl;
print(39);
}
if(now==2)
{
print(13);
cout<<"West player:"<<endl;
print(26);
cout<<"North player:"<<endl;
print(39);
cout<<"East player:"<<endl;
print(0);
}
if(now==1)
{
print(26);
cout<<"West player:"<<endl;
print(39);
cout<<"North player:"<<endl;
print(0);
cout<<"East player:"<<endl;
print(13);
}
if(now==0)
{
print(39);
cout<<"West player:"<<endl;
print(0);
cout<<"North player:"<<endl;
print(13);
cout<<"East player:"<<endl;
print(26);
}
cout<<endl;
}
return 0;
}
D - 走迷宫
题意
在一个5* 5的迷宫中从(0,0)走到(4,4),迷宫直接通过5*5的二维数组给出,0为可走,1为不可走。找到最短路径并输出。
思路
从迷宫的入口开始,进行BFS遍历,BFS遍历的关键就是需要用到一个队列,在这道题中,只需要从入口点出发,依次看下它的上下左右四个结点是否可以走(值为0或1),如果可以走,就立即把这个结点存入队列中,并将该节点的值置为1,然后每次找的时候就是从队头取出一个点,依次看它的上下左右四个方向即可。不过由于要输出最短路径,因此需要额外开辟一个二维数组来记录父节点(即路径上的上一个节点),最后通过这一数组递归输出最短路径。
代码
#include <iostream>
#include <stdio.h>
#include <queue>
#include <string.h>
using namespace std;
struct point
{
int x,y;
point(){}
point(int a,int b){
x=a;
y=b;
}
};
point f[5][5];//用于记录父节点
void print(int x,int y)//递归输出最短路径
{
if(f[x][y].x!=x||f[x][y].y!=y)
print(f[x][y].x, f[x][y].y);
printf("(%d, %d)\n", x, y);
}
int main()
{
int a[5][5],dis[5][5];
bool b[5][5];
for(int i=0;i<5;i++)
for(int j=0;j<5;j++)
{
cin>>a[i][j];
b[i][j] = false;
dis[i][j] = 0;
f[i][j] = point(i,j);
}
int dx[]={ 0, 0, 1, -1};
int dy[]={ 1, -1, 0, 0};
queue<point> q;
point s(0,0);
q.push(s);
b[0][0]=true;
while(!q.empty())
{
point now = q.front();
q.pop();
for(int i=0;i<4;i++){
int x = now.x+dx[i];
int y = now.y+dy[i];
if( x>=0 && x<=4 && y>=0 && y<=4 && !a[x][y]&& !b[x][y])
{
f[x][y] = point( now.x, now.y);
dis[x][y] = dis[now.x][now.y] + 1;
b[x][y] = true;
q.push(point(x,y));
}
}
}
print(4,4);
return 0;
}
E - Pour Water
题意
有A、B两个杯子,通过装满、倒空、将一个杯子中的水倒入另一个杯子中,最后使杯A杯或者B杯中含有C单位的水。输入直接为A、B、C三个数字,表示A、B两个杯子和要求的C单位水。
思路
这一题与上一题的思路基本相同,只不过走迷宫时只有四个方向可以选择,而这次有六种选择,empty A,empty B,fill A,fill B,pour A B,pour B A;只不过与上一题不一样这次记录操作的方式不同,可以向结构体增加一个变量来记录,也可以通过map来解决;我选择的是map,通过建立ma结构体和申请map<ma, int>来记录每一个操作,最后再递归输出。
代码
#include <iostream>
#include <stdio.h>
#include <queue>
#include <map>
using namespace std;
int a, b, c;
struct cup{
int x, y;
cup(){}
cup(int a,int b){
x=a;
y=b;
}
bool operator<(const cup &s) const
{
return x!=s.x ? x<s.x : y<s.y;
}
bool operator!=(const cup &s) const
{
return x!=s.x || y!=s.y;
}
cup AtoB(){
cup c;
c.x = max( x+y-b, 0);
c.y = min( x+y, b);
return c;
}
cup BtoA(){
cup c;
c.y = max( x+y-a, 0);
c.x = min( x+y, a);
return c;
}
cup FILLA(){
cup c;
c.x = a;
c.y = y;
return c;
}
cup FILLB(){
cup c;
c.x = x;
c.y = b;
return c;
}
cup EmptyA(){
cup c;
c.x = 0;
c.y = y;
return c;
}
cup EmptyB(){
cup c;
c.x = x;
c.y = 0;
return c;
}
};
struct ma{
cup x1, y1;
bool operator<(const ma &s) const
{
return x1!=s.x1 ? x1<s.x1 : y1<s.y1;
}
ma(cup a,cup b){
x1 = a;
y1 = b;
}
};
map<cup , cup> f;
map<cup , bool> v;
queue<cup> q;
map<ma, int> x;
void change(cup s, cup s1){
if(!v[s])
{
v[s]=true;
f[s]=s1;
q.push(s);
}
}
void print(cup s){
cup a = f[s];
if(f[a]!=a)
print(a);
int b = x[ma(s,a)];
if(b==1)
cout<<"pour A B"<<endl;
if(b==2)
cout<<"pour B A"<<endl;
if(b==3)
cout<<"fill A"<<endl;
if(b==4)
cout<<"fill B"<<endl;
if(b==5)
cout<<"empty A"<<endl;
if(b==6)
cout<<"empty B"<<endl;
}
int main(){
while(scanf("%d%d%d",&a,&b,&c)!=EOF)
{
while(!q.empty())
q.pop();
v.clear();
cup s(0, 0);
f[s] = s;
q.push(s);
v[s] = true;
while(!q.empty())
{
cup now = q.front();
q.pop();
if(now.x == c||now.y==c)
{
print(now);
cout<<"success"<<endl;
break;
}
change(now.AtoB(),now);
x[ma(now.AtoB(),now)] = 1;
change(now.BtoA(),now);
x[ma(now.BtoA(),now)] = 2;
change(now.FILLA(),now);
x[ma(now.FILLA(),now)] = 3;
change(now.FILLB(),now);
x[ma(now.FILLB(),now)] = 4;
change(now.EmptyA(),now);
x[ma(now.EmptyA(),now)] = 5;
change(now.EmptyB(),now);
x[ma(now.EmptyB(),now)] = 6;
}
}
return 0;
}