作业题
题目地址
A-Maze
题意: 经典迷宫问题,输入5×5的二维数组表示迷宫,0表示可以走,1表示不可以走,要求输出从入口 (0,0)到出口(4,4)的最短路径。思路: BFS板子题,为了记录路径,在结构体中添加记录父节点的变量,使用以head、tail指针维护的结构体数组作为队列,先将(0,0)入队,从起点开始,执行一次BFS直到队头元素为终点结束,然后从此时的队头元素开始,向前回溯直到父节点为起点为止以记录下路径,最后输出路径。代码实现:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
using namespace std;
bool maze[ 5 ] [ 5 ] ;
bool vis[ 5 ] [ 5 ] ;
int dis[ ] [ 2 ] = { { 1 , 0 } , { - 1 , 0 } , { 0 , - 1 } , { 0 , 1 } } ;
struct s{
int x, y, father, steps;
s ( ) { }
s ( int xx, int yy, int ff, int ss) : x ( xx) , y ( yy) , father ( ff) , steps ( ss) { }
} ;
bool Range ( int x, int y) {
if ( x>= 0 && x<= 4 && y>= 0 && y<= 4 && maze[ x] [ y] == 0 && vis[ x] [ y] == 0 )
return true ;
return false ;
}
int main ( )
{
for ( int i= 0 ; i< 5 ; i++ ) {
for ( int j= 0 ; j< 5 ; j++ ) {
cin>> maze[ i] [ j] ;
}
}
memset ( vis, 0 , sizeof ( vis) ) ;
s q[ 10000 ] ;
int head= 0 ;
int tail= 0 ;
q[ tail++ ] = s ( 0 , 0 , - 1 , 0 ) ;
vis[ 0 ] [ 0 ] = 1 ;
while ( head!= tail) {
s t= q[ head] ;
if ( t. x== 4 && t. y== 4 ) {
break ;
}
for ( int i= 0 ; i< 4 ; i++ ) {
int dx= t. x+ dis[ i] [ 0 ] ;
int dy= t. y+ dis[ i] [ 1 ] ;
if ( Range ( dx, dy) ) {
vis[ dx] [ dy] = 1 ;
q[ tail++ ] = s ( dx, dy, head, t. steps+ 1 ) ;
}
}
head++ ;
}
vector< s> res;
s tmp= q[ head] ;
while ( tmp. father!= - 1 ) {
res. push_back ( tmp) ;
tmp= q[ tmp. father] ;
}
cout<< "(0, 0)" << endl;
for ( int i= res. size ( ) - 1 ; i>= 0 ; i-- ) {
cout<< "(" << res[ i] . x<< ", " << res[ i] . y<< ")" << endl;
}
return 0 ;
}
#include <bits/stdc++.h>
using namespace std;
const int inf= 1e9 ;
int maze[ 10 ] [ 10 ] , dis[ ] [ 2 ] = { { 1 , 0 } , { - 1 , 0 } , { 0 , 1 } , { 0 , - 1 } } ;
bool vis[ 10 ] [ 10 ] ;
bool Range ( int x, int y) {
if ( x>= 0 && x<= 4 && y>= 0 && y<= 4 && maze[ x] [ y] == 0 && vis[ x] [ y] == 0 )
return true ;
return false ;
}
struct node{
int x, y;
node ( ) { }
node ( int xx, int yy) : x ( xx) , y ( yy) { }
} ;
vector< node> path;
bool dfs ( int x, int y) {
if ( x== 4 && y== 4 ) {
path. push_back ( node ( x, y) ) ;
return true ;
}
vis[ x] [ y] = 1 ;
bool flag= false ;
if ( Range ( x, y+ 1 ) && dfs ( x, y+ 1 ) || Range ( x+ 1 , y) && dfs ( x+ 1 , y) ||
Range ( x- 1 , y) && dfs ( x- 1 , y) || Range ( x, y- 1 ) && dfs ( x, y- 1 ) ) {
path. push_back ( node ( x, y) ) ;
return true ;
}
return false ;
}
int main ( )
{
for ( int i= 0 ; i< 5 ; i++ ) {
for ( int j= 0 ; j< 5 ; j++ ) {
scanf ( "%d" , & maze[ i] [ j] ) ;
vis[ i] [ j] = 0 ;
}
}
vis[ 0 ] [ 0 ] = 1 ;
dfs ( 0 , 0 ) ;
for ( int i= path. size ( ) - 1 ; i>= 0 ; i-- )
printf ( "(%d, %d)\n" , path[ i] . x, path[ i] . y) ;
return 0 ;
}
#include <bits/stdc++.h>
using namespace std;
const int inf= 1e9 ;
const int maxn= 1e4 ;
int ans= inf, maze[ 10 ] [ 10 ] , dis[ ] [ 2 ] = { { 1 , 0 } , { - 1 , 0 } , { 0 , 1 } , { 0 , - 1 } } ;
bool vis[ 10 ] [ 10 ] ;
bool Range ( int x, int y) {
if ( x>= 0 && x<= 4 && y>= 0 && y<= 4 && maze[ x] [ y] == 0 && vis[ x] [ y] == 0 )
return true ;
return false ;
}
struct node{
int x, y;
node ( ) { }
node ( int xx, int yy) : x ( xx) , y ( yy) { }
} ;
node path[ maxn] , tmp[ maxn] ;
void dfs ( int x, int y, int steps) {
if ( x== 4 && y== 4 ) {
if ( ans> steps) {
ans= steps;
tmp[ steps] . x= x;
tmp[ steps] . y= y;
for ( int i= 1 ; i<= steps; i++ )
path[ i] = tmp[ i] ;
}
return ;
}
for ( int i= 0 ; i< 4 ; i++ ) {
int dx= x+ dis[ i] [ 0 ] ;
int dy= y+ dis[ i] [ 1 ] ;
if ( Range ( dx, dy) ) {
tmp[ steps] . x= x;
tmp[ steps] . y= y;
vis[ dx] [ dy] = 1 ;
dfs ( dx, dy, steps+ 1 ) ;
vis[ dx] [ dy] = 0 ;
}
}
}
int main ( )
{
for ( int i= 0 ; i< 5 ; i++ ) {
for ( int j= 0 ; j< 5 ; j++ ) {
scanf ( "%d" , & maze[ i] [ j] ) ;
vis[ i] [ j] = 0 ;
}
}
vis[ 0 ] [ 0 ] = 1 ;
dfs ( 0 , 0 , 0 ) ;
for ( int i= 0 ; i<= ans; i++ )
printf ( "(%d, %d)\n" , path[ i] . x, path[ i] . y) ;
return 0 ;
}
B-Pour Water
题意: 有两个体积分别为A、B的容器,容器的起始状态为空,要求通过执行fill a/b、empty a(b) b(a)、pour a(b) b(a)六种操作使其中一个容器中装有体积为C的水,记录并输出操作过程思路: BFS隐式图问题,以两个容器中盛有水的体积作为本题的状态则初始结点为(0,0),目标结点为(C,0)或(0,C),中间结点为经过不同操作后容器中的盛水状态,实现思路与A题相似,从初始结点开始执行一次BFS直到队头元素为目标结点,从此时的队头元素开始向前回溯记录路径,最后输出操作过程。代码实现:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
using namespace std;
int a, b, c;
bool vis[ 1010 ] [ 1010 ] ;
struct s{
int pot1;
int pot2;
int steps;
int op;
int father;
s ( ) { }
s ( int p1, int p2, int s, int o, int f) : pot1 ( p1) , pot2 ( p2) , steps ( s) , op ( o) , father ( f) { }
} ;
s q[ 1000000 ] ;
void Output ( int op) {
switch ( op) {
case 0 :
cout<< "fill A" << endl;
break ;
case 1 :
cout<< "fill B" << endl;
break ;
case 2 :
cout<< "empty A" << endl;
break ;
case 3 :
cout<< "empty B" << endl;
break ;
case 4 :
cout<< "pour A B" << endl;
break ;
case 5 :
cout<< "pour B A" << endl;
break ;
}
}
int main ( )
{
ios:: sync_with_stdio ( false ) ;
while ( cin>> a>> b>> c) {
memset ( vis, 0 , sizeof ( vis) ) ;
int head, tail;
head= tail= 0 ;
vis[ 0 ] [ 0 ] = 1 ;
q[ tail++ ] = s ( 0 , 0 , 0 , - 1 , - 1 ) ;
while ( head!= tail) {
s t= q[ head] ;
if ( t. pot1== c|| t. pot2== c) {
break ;
}
if ( ! vis[ a] [ t. pot2] ) {
vis[ a] [ t. pot2] = 1 ;
q[ tail++ ] = s ( a, t. pot2, t. steps+ 1 , 0 , head) ;
}
if ( ! vis[ t. pot1] [ b] ) {
vis[ t. pot1] [ b] = 1 ;
q[ tail++ ] = s ( t. pot1, b, t. steps+ 1 , 1 , head) ;
}
if ( ! vis[ 0 ] [ t. pot2] ) {
vis[ 0 ] [ t. pot2] = 1 ;
q[ tail++ ] = s ( 0 , t. pot2, t. steps+ 1 , 2 , head) ;
}
if ( ! vis[ t. pot1] [ 0 ] ) {
vis[ t. pot1] [ 0 ] = 1 ;
q[ tail++ ] = s ( t. pot1, 0 , t. steps+ 1 , 3 , head) ;
}
int sum= t. pot1+ t. pot2;
if ( sum> b) {
if ( ! vis[ sum- b] [ b] ) {
vis[ sum- b] [ b] = 1 ;
q[ tail++ ] = s ( sum- b, b, t. steps+ 1 , 4 , head) ;
}
}
if ( sum<= b) {
if ( ! vis[ 0 ] [ sum] ) {
vis[ 0 ] [ sum] = 1 ;
q[ tail++ ] = s ( 0 , sum, t. steps+ 1 , 4 , head) ;
}
}
if ( sum> a) {
if ( ! vis[ a] [ sum- a] ) {
vis[ a] [ sum- a] = 1 ;
q[ tail++ ] = s ( a, sum- a, t. steps+ 1 , 5 , head) ;
}
}
if ( sum<= a) {
if ( ! vis[ sum] [ 0 ] ) {
vis[ sum] [ 0 ] = 1 ;
q[ tail++ ] = s ( sum, 0 , t. steps+ 1 , 5 , head) ;
}
}
head++ ;
}
vector< s> res;
s path= q[ head] ;
while ( path. father!= - 1 ) {
res. push_back ( path) ;
path= q[ path. father] ;
}
for ( int i= res. size ( ) - 1 ; i>= 0 ; i-- ) {
Output ( res[ i] . op) ;
}
cout<< "success" << endl;
}
return 0 ;
}
实验题:
题目地址
A
题意: 由5个烷烃基的原子与化学键的连接方式寻找规律,要求判断输入数据所属的烷烃基的类别。思路: 将原子转换为结点,化学键转换为连接两个结点的边,根据输入数据构图。通过统计图中结点的最大度可将烷烃基大致分为4类;然后通过观察2-methylpentane 与3-methylpentane 的结构看出,图中与最大度结点距离最远的结点到达最大度结点的最短路径为3的是2-methylpentane ,为2的是3-methylpentane 。故本题的做法总结为:首先计算图中结点的最大度数进行判断,若此时无法得出结论再从图中最大度数结点开始执行一次BFS记录遍历图的最短路径进行比较判断。代码实现:
#include <iostream>
#include <algorithm>
#include <iostream>
#include <queue>
#include <cstring>
using namespace std;
int g[ 10 ] [ 10 ] ;
bool vis[ 10 ] ;
struct node{
int i;
int steps;
node ( int ii, int ss) {
i= ii;
steps= ss;
}
node ( ) {
}
} ;
int main ( )
{
int t, a, b;
cin>> t;
while ( t-- ) {
int mp[ 10 ] ;
memset ( mp, 0 , sizeof ( mp) ) ;
memset ( g, 0 , sizeof ( g) ) ;
for ( int i= 0 ; i< 5 ; i++ ) {
cin>> a>> b;
g[ a] [ b] = g[ b] [ a] = 1 ;
mp[ a] ++ ;
mp[ b] ++ ;
}
int max= 0 ;
int id;
for ( int i= 1 ; i<= 6 ; i++ ) {
if ( max< mp[ i] ) {
max= mp[ i] ;
id= i;
}
}
if ( max== 4 )
cout<< "2,2-dimethylbutane" << endl;
else if ( max== 3 ) {
bool flag= false ;
for ( int i= 1 ; i<= 6 ; i++ ) {
if ( mp[ i] == 3 && i!= id) {
cout<< "2,3-dimethylbutane" << endl;
flag= true ;
}
}
if ( ! flag) {
queue< node> q;
q. push ( node ( id, 0 ) ) ;
memset ( vis, 0 , sizeof ( vis) ) ;
vis[ id] = 1 ;
int dis= 0 ;
while ( ! q. empty ( ) ) {
node t= q. front ( ) ;
q. pop ( ) ;
for ( int i= 1 ; i<= 6 ; i++ ) {
if ( g[ t. i] [ i] != 0 && vis[ i] != 1 ) {
vis[ i] = 1 ;
q. push ( node ( i, t. steps+ 1 ) ) ;
if ( t. steps+ 1 > dis)
dis= t. steps+ 1 ;
}
}
}
if ( dis== 2 )
cout<< "3-methylpentane" << endl;
else
cout<< "2-methylpentane" << endl;
}
}
else
cout<< "n-hexane" << endl;
}
return 0 ;
}
B
题意: OJ的排名功能实现:给定题数与单位罚时,输入多组学生的数据,按照题目要求进行排名,最后格式化输出排名结果。思路: 本题主要考察多关键字结构体排序与格式化输出,首先声明结构体stu,包含姓名、题数、总用时三个属性,并根据题目所给的排序规则重载运算符 < 。由于学生数未知,故将学生结构体数组开大,并在输入过程中用size来记录当前输入数据所对应的索引。对于每次输入的数据利用string类的find函数判断是否存在’('以确定是否存在罚时,利用atoi函数将字符串转换为整数进行计算,最后对结构体数组进行排序并格式化输出结果。代码实现:
#include <iostream>
#include <string>
#include <algorithm>
#include <iomanip>
using namespace std;
struct stu{
string name;
int num;
int time;
friend bool operator < ( stu & s1, stu & s2) {
if ( s1. num!= s2. num) {
return s1. num> s2. num;
}
else {
if ( s1. time!= s2. time) {
return s1. time< s2. time;
}
else
return s1. name< s2. name;
}
}
} ;
stu Rank[ 200000 ] ;
int main ( )
{
int n, m;
cin>> n>> m;
string input;
int i= 0 ;
int j= 0 ;
int size= - 1 ;
string s[ 20 ] ;
while ( cin>> input) {
j= i% ( n+ 1 ) ;
if ( j== 0 )
Rank[ ++ size] . name= input;
else
s[ j] = input;
string:: size_type idx;
idx= s[ j] . find ( '(' ) ;
if ( idx!= string:: npos) {
string c= s[ j] ;
string a;
string b;
for ( int k= 0 ; k< c. size ( ) ; k++ ) {
if ( c[ k] == '(' ) {
for ( int p= k+ 1 ; p< c. size ( ) - 1 ; p++ )
a+ = c[ p] ;
break ;
}
b+ = c[ k] ;
}
int err= atoi ( a. c_str ( ) ) ;
int ys= atoi ( b. c_str ( ) ) ;
Rank[ size] . num++ ;
Rank[ size] . time+ = ys;
Rank[ size] . time+ = err* m;
}
else {
int cost= atoi ( s[ j] . c_str ( ) ) ;
if ( cost> 0 ) {
Rank[ size] . num++ ;
Rank[ size] . time+ = cost;
}
}
i++ ;
}
sort ( Rank, Rank+ size+ 1 ) ;
for ( int i= 0 ; i<= size; i++ ) {
cout<< left<< setw ( 10 ) << Rank[ i] . name<< " " ;
cout<< right<< setw ( 2 ) << Rank[ i] . num<< " " ;
cout<< right<< setw ( 4 ) << Rank[ i] . time;
cout<< endl;
}
return 0 ;
}
C
题意: 指定发牌员,顺时针循环发牌,最后从小到大排序每个人手中的牌,并按照给定格式输出。思路: 本题也是多关键字结构体排序问题,首先声明结构体s,为了方便排序,使用char a表示花色,int b表示牌面的值,其中花色按照字典序进行排序(对S与H的比较进行单独处理),牌面的值首先将T、J、Q、K、A分别映射到10、11、12、13、14然后按照整数的升序进行排序。由于每个人的元素是确定的都为13个,故将4个人的数据分段存入一个结构体数组内,然后对每段调用STL的sort函数进行排序,最后格式化输出结果。代码实现:
#include <iostream>
#include <algorithm>
#include <string>
#include <map>
#include <cstring>
using namespace std;
struct s{
char a;
int b;
s ( ) { }
s ( char aa, int bb) : a ( aa) , b ( bb) { }
friend bool operator < ( const s & s1, const s & s2) {
if ( s1. a!= s2. a) {
if ( ( s1. a== 'S' && s2. a== 'H' ) || ( s1. a== 'H' && s2. a== 'S' ) )
return s1. a> s2. a;
else
return s1. a< s2. a;
}
else
return s1. b< s2. b;
}
} ;
s a[ 60 ] ;
int dindex[ 10 ] = { 0 , 13 , 26 , 39 } ;
map< char , int > mp;
map< int , char > P;
char beginer;
void Output1 ( int f, int t)
{
for ( int i= f; i<= t; i++ ) {
if ( i== f)
cout<< "|" ;
if ( a[ i] . b>= 10 && a[ i] . b<= 14 ) {
cout<< P[ a[ i] . b] << " " << P[ a[ i] . b] << "|" ;
}
else
cout<< a[ i] . b<< " " << a[ i] . b<< "|" ;
}
}
void Output ( int f, int t)
{
cout<< "+---+---+---+---+---+---+---+---+---+---+---+---+---+" << endl;
Output1 ( f, t) ;
cout<< endl;
for ( int i= f; i<= t; i++ ) {
if ( i== f)
cout<< "|" ;
cout<< " " << a[ i] . a<< " " << "|" ;
}
cout<< endl;
Output1 ( f, t) ;
cout<< endl;
cout<< "+---+---+---+---+---+---+---+---+---+---+---+---+---+" << endl;
}
int main ( )
{
ios:: sync_with_stdio ( false ) ;
mp[ 'N' ] = 0 ; mp[ 'E' ] = 1 ; mp[ 'S' ] = 2 ; mp[ 'W' ] = 3 ;
mp[ 'T' ] = 10 ; mp[ 'J' ] = 11 ; mp[ 'Q' ] = 12 ; mp[ 'K' ] = 13 ; mp[ 'A' ] = 14 ;
P[ 10 ] = 'T' ; P[ 11 ] = 'J' ; P[ 12 ] = 'Q' ; P[ 13 ] = 'K' ; P[ 14 ] = 'A' ;
while ( cin>> beginer) {
if ( beginer== '#' )
break ;
int cursor= mp[ beginer] + 1 ;
char input1, input2;
for ( int i= 0 ; i< 52 ; i++ ) {
cin>> input1>> input2;
a[ dindex[ cursor% 4 ] ] . a= input1;
if ( input2>= '2' && input2<= '9' )
a[ dindex[ cursor% 4 ] ++ ] . b= input2- '0' ;
else
a[ dindex[ cursor% 4 ] ++ ] . b= mp[ input2] ;
cursor= ( cursor+ 1 ) % 4 ;
}
sort ( a, a+ 13 ) ;
sort ( a+ 13 , a+ 26 ) ;
sort ( a+ 26 , a+ 39 ) ;
sort ( a+ 39 , a+ 52 ) ;
cout<< "South player:" << endl;
Output ( 26 , 38 ) ;
cout<< "West player:" << endl;
Output ( 39 , 51 ) ;
cout<< "North player:" << endl;
Output ( 0 , 12 ) ;
cout<< "East player:" << endl;
Output ( 13 , 25 ) ;
cout<< endl;
dindex[ 0 ] = 0 ; dindex[ 1 ] = 13 ; dindex[ 2 ] = 26 ; dindex[ 3 ] = 39 ;
}
return 0 ;
}
总结:
作业 :BFS的两道典型例题,其中需要注意的是每次BFS前一定要初始化 访问数组和存储路径的数组,对于隐式图问题要先按照题意,将题目条件转换为BFS中的状态信息 ,尤其需要注意初始结点、目标结点以及搜索时约束条件的确定。实验 :其实三道题目的难度都不大,但是最后结果却全部挂零,主要原因是做题太过浮躁,在以后的做题过程中一定要好好调整心态。A题是图论的简单应用,但由于题目存在多组数据,在每次构图后没有重置邻接矩阵 而导致了wa,但课上并未静下心去调试而是转向了B题,在读题时惯性思维,将n(题目数量)当成了学生数量 ,由于没想到是输入出问题,故一直将重点放在了计算部分和可能导致数组越界的部分,在每层循环输入结束后输出的结果正确但跳出后无输出(当时以为遇到了玄学……),然后就和B题奋战到了下课……(但凡重新读遍题或者在输入那打个断点也不至于这么惨2333)C题同样也是一道结构体排序的题目,但提交后一直re,这个debug的历程更加一言难尽……由于样例输出正确且数据个数为52是固定的,那么按常理来说,结构体数组的索引应该没有问题,然后通过查资料了解到map重载的"[]"运算符使用不当可能会导致Segmentation Fault,故将搜索操作用find函数替代,并在赋值前判断是否已经成功返回正确位置的迭代器,又将插入操作改为insert,然后输出插入结果,发现并未出现问题(what a bad day!),此时心态崩得不行的我随便输入数据进行测试,发现在输入了多组数据后程序崩溃,然后从第3组开始,出现了奇怪的结果,此时突然想到维护结构体数组的索引在每次操作之后没有更新 ,从而导致了结构体数组的越界,这次实验凉在了初始化上,以后要么用动态数组然后clear要么记住每层循环结束后初始化。