2012年北邮网研院复试上机题目
2012.网研院.Problem A.打印字符串
链接1: http://10.105.242.83/problem/132 链接2: http://10.105.242.80/problem/p/99
题目描述
老师有一个问题想考考mabo,但是mabo不会,所以想请你来帮帮忙。
问题如下:
给一串字符串,统计其中某个字符的个数。
输入格式
首先输入一个整数T,表示一共有T组数据 0<T<=10。
接下来每行一个字母x(x为’a’-'z’或者‘A’-‘Z’)。
然后下面一行输入一个字符串s(0<s的长度<1000)。
输出格式
统计这个字母在这个字符串中出现的次数
输入样例
2
a
absd
b
bbssb
输出样例
1
3
代码实现
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int T;
cin >> T;
int count[10] = {0};
char c;
char s[1000];
int i, j;
for( i = 0; i < T; i++ )
{
cin >> c;
cin >> s;
for( j = 0; j < strlen(s); j++ )
if( s[j] == c )
count[i]++;
}
for( i = 0; i < T; i++ )
cout << count[i] << endl;
return 0;
}
2012.网研院.Problem B.二叉树的层数
链接1: http://10.105.242.83/problem/133 链接2: http://10.105.242.80/problem/p/100
题目描述
老师有一个问题想考考mabo,但是mabo不会,所以想请你来帮帮忙。
问题如下:
给一个二叉树
请把这个棵二叉树按层来打印。如果为相同层,需要从左到右打印。一个节点是先添加左节点后添加右节点,即添加顺序与输入顺序一致。
输入格式
首先输入一个整数T,表示一共有T组数据 0<T<=10
再输入两个整数N,M(0<=N,M<=100)
表示下面有N行,这个树有M个节点(1号节点是这棵树的根节点)
每一行两个整数a,b(1<=a,b<=M)
表示节点a的父亲是节点b
输出格式
对于每组
先输出一行 "Qi:"表示第i个问题
然后接下来输出每个问题二叉树每层的节点,在同一层的节点用空格分开,同一层输出在一行(每一行末尾没有空格),不同的层输出在不同行(入下面Sample Ouput所示)
输入样例
2
4 5
2 1
3 1
4 2
5 4
1 2
2 1
输出样例
Q1:
1
2 3
4
5
Q2:
1
2
思路
此题使用二叉树模板,定义节点、构造节点并且初始化、构造树
用递归的方法 求树的深度
树的层次遍历
代码实现
#include <iostream>
#include <queue>
using namespace std;
const int maxsize = 500;
///二叉树模板
typedef struct BiNode
{
int data;
int lc; ///左孩子的数组下标
int rc; ///右孩子的数组下标
int deep;
bool turnOn; ///此二叉树节点是否有效
BiNode()
{
initNode();
}
void initNode()
{
turnOn = false;
deep = -1;
lc = rc = -1;
}
};
BiNode Tree[maxsize]; ///用一维数组来存储一颗二叉树
int cursor;
int t, n, m;
int createNode( int index ) ///在数组下标 x 处创造一个节点
{
Tree[index].data = index;
Tree[index].turnOn = true;
Tree[index].lc = Tree[index].rc = -1;
return index;
}
void creatTree()
{
int a,b; /// a 的 父节点是 b;
createNode(0); ///创建根节点
cin >> n >> m; /// n 行 m 个 节点
while( n-- )
{
cin >> a >> b;
a--; b--;
createNode( a ); ///创建 a 节点
if( Tree[b].lc == -1 ) /// 无座孩子 先写入左孩子
Tree[b].lc = a;
else
Tree[b].rc = a;
}
}
void freeNode( int index )
{
Tree[index].initNode();
}
void freeTree( int index ) ///采用递归的方式释放一棵树( 后序方式 )
{
if( index == -1 ) /// 递归出口
return;
freeTree( Tree[index].lc ); ///递归删除左子树
freeTree( Tree[index].rc ); ///递归删除右子树
Tree[index].initNode(); ///删除根节点
}
void calDeep( int root, int nowDeep ) ///先序递归方式求出各节点所在的层次
{
if( root == -1 )
return;
Tree[root].deep = nowDeep;
calDeep( Tree[root].lc, nowDeep+1 );
calDeep( Tree[root].rc, nowDeep+1 );
}
void levelOrder( int root ) ///从第 nowDeep 层开始 非递归的层次遍历root 为根节点的二叉树
{
bool firstCase = true;
int nowDeep = 1;
queue<BiNode> q;
while( !q.empty() ) ///队列初始化
q.pop();
q.push( Tree[root] ); ///根节点入队
while( !q.empty() )
{
BiNode &nowNode = q.front();
q.pop();
if( nowNode.deep != nowDeep ) ///到了下一层
{
cout << endl;
nowDeep++;
firstCase = true;
}
if( firstCase )
firstCase = false;
else
cout << " ";
cout << nowNode.data+1; ///访问节点
if( nowNode.lc != -1 )
q.push( Tree[nowNode.lc] );
if( nowNode.rc != -1 )
q.push( Tree[nowNode.rc] );
}
}
int main()
{
int T;
cin >> T;
for( int time = 0; time < T; time++ )
{
for( int i = 0; i < maxsize; i++ )
Tree[i].initNode();
creatTree();
calDeep(0, 1);
cout << "Q" << time+1 << ":" << endl;
levelOrder(0);
cout << endl;
}
return 0;
}
2012.网研院.Problem C. IP地址
链接1: http://10.105.242.83/problem/134 链接2: http://10.105.242.80/problem/p/101
题目描述
我们都学过计算机网络,了解IPV4地址的点分十进制表示法。
你的任务很简单:判断一个字符串是否是一个合法的点分十进制表示的IPV4地址。
最低的IP地址是0.0.0.0,最高的IP地址是255.255.255.255。
PS :方便起见,认为形似00.00.00.00的IP地址也是合法的。
输入格式
第一行是一个整数T,代表输入还剩下T行
以下的T行,每行都是一个字符串(不含空白字符)。字符串的长度保证不超过15,不小于1.
输出格式
对于每个字符串,输出一行。
如果它是一个合法的IPV4地址,输出Yes。
否则,输出No。
输入样例
3
59.64.130.18
f.a.t.e
1.23.45.678
输出样例
Yes
No
No
思路一
Ip地址 三个点 四串数字
错误思路1:当前字符为数字时,设 num 记录数字
当前字符为 “.” 时, 数点数量,超3停止。同时 如果num 不为 0,设num = 0, 如果num = 0,则前一个字符也是点,停止
这种思路是错的,因为 0.0.0.0 也是合法的。
正确思路:为数字时,如果前一字符是 ‘.’,则数字计数++, 记录当前数字,判断是否超过255
为 ‘.’ 时,判断前一个字符是是否也为 ‘.’ ,同时点计数++。
代码实现
#include <iostream>
#include <string>
using namespace std;
int main()
{
int T;
cin >> T;
string str;
for(int i = 0; i < T; i++ )
{
int countdot = 0;
int countnet = 0;
int net = 0;
bool flag = true;
cin >> str;
for(int j = 0; j < str.size(); j++ )
if( isdigit(str[j]))
{
if( j == 0 || str[j-1] == '.' )
countnet++;
net = net * 10 + str[j] - '0';///cout << " net = " << net << endl;
if( net > 255 )
{
flag = false;
break;
}
}
else if( str[j] == '.' )
{
countdot++;
if( countdot > 3 || str[j-1] == '.' )
{
flag = false;
break;
}
else
net = 0;
}
else
{
flag = false;
break;
}
if( flag && countnet == 4 )
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
思路二:
这题着实是坑爹了。所以总结题目的意思是:各种非法输入都可能发生,所有情况都得考虑到。故最佳方法就是用
scanf("%d.%d.%d.%d%c",&x[0],&x[1],&x[2],&x[3],&c);
来进行判断是否输入合法。
然而倘若如此,若最后一个%d处没有输入元素,则程序会一直等待输入流输入一个数字,导致无法进行下去。而且使用此法的话当后续串没有被读入时,还得追加一个字符串读入函数进行后处理,十分的麻烦
解决的方法就是先将本行输入全部装入str串里头,然后使用sscanf进行读取,这样首先免去了末尾对费串的后处理,而且由于sscanf读的是str串,故在最后的%d处若没有元素可读会直接读取失败,而不会等待,因为str串的字符流是确定的,缺少数字元素就是缺少,不会继续等待录入。然后在最后追加一个%c,如果后面有费串则sscanf的返回值会+1。通过判断
scanf("%d.%d.%d.%d%c",&x[0],&x[1],&x[2],&x[3],&c);
符合这样格式的输入的返回值是否严格==4,即可从格式上来界定此次输入是否合法,若合法紧接着只要专心对数字范围进行界定即可。
本题要学到的一个重要技巧就是sscanf()函数的使用,可以方便地从串字符流中读取,模拟scanf从输入流中读取。并且比后者有着不会一直傻等输入的优点。
代码实现
#include <iostream>
#include <cstdio>
#include <cstring>
#define INF 0x7fffffff
#define MAXSIZE 20
using namespace std;
int main(){
int t;
int x[4];
char str[MAXSIZE];
char c;
bool legal;
int count;
scanf("%d",&t);
while (t--){
//initiate
legal=true;
//input
scanf("%s",str);
count=sscanf(str,"%d.%d.%d.%d%c",&x[0],&x[1],&x[2],&x[3],&c);
if (count!=4){//各种输入不合法全囊括在这个判断里
//即:输入不按照格式,中间夹带非法字符,末尾有非法字符,分隔符之间没有元素 等
legal=false;
}
else{//输入为n.n.n.n格式
for (int i=0;i<4;i++){
if (x[i]<0||x[i]>255){
legal=false;
break;
}
}
}
//output
printf("%s\n",legal?"Yes":"No");
}
return true;
}
2012.网研院.Problem D.最远距离
链接1: http://10.105.242.83/problem/135 链接2: http://10.105.242.80/problem/p/102
题目描述
正义的伙伴褋祈和葬仪社的机器人Fuyuneru正在被邪恶的GHQ部队追杀。眼看着快要逃不掉了,祈就把重要的东西塞到了机器人体内,让它先跑,自己吸引火力。
假设Fuyuneru带上东西开始逃跑时所处的点为原点,朝向为正北。操纵FuyuNeru的指令有如下四种:
right X: X是1-359之间的整数,Fuyuneru的前进方向顺时针转X度。
left X: X是1-359之间的整数,Fuyuneru的前进方向逆时针转X度。
forward X: X是整数(0<=X<=1000),Fuyuneru向当前朝向前进X米。
backward X: X是整数(0<=X<=1000),Fuyuneru向当前朝向后退X米。
现在祈向Fuyuneru体内输入了N(1<=N<=50)个这样的指令。可是由于此前Fuyuneru被GHQ部队击中,它出了一点小问题:这N个指令执行的顺序是不确定的。
问:Fuyuneru最远可能逃出多远?
即,Fuyuneru在执行完N条指令之后,距离原点最远的可能距离是多少?
输入格式
第一行是一个整数T,代表测试数据有T组。
每组测试数据中,第一行是一个整数N,代表指令有N条;
随后紧跟N行,每一行代表一个指令(格式保证是上述四种中的一种,数据保证合法)
输出格式
对于每组数据,输出一行:最远的可能逃亡距离,精确到小数点后3位。
输入样例
3
3
forward 100
backward 100
left 90
4
left 45
forward 100
right 45
forward 100
6
left 10
forward 40
right 30
left 10
backward 4
forward 4
输出样例
141.421
200.000
40.585
思路
此题最远距离可分为 3 部分
1.向前走
2.找出旋转角度最接近180的组合
3.向后走
4.剩下的角度不会对结果产生影响
即问题转化为 在一个数组中找 若干个数 使其和 mod 360 接近 180 (背包问题)
代码实现
bool visit[maxn]; //表示角度是否使用过
bool agl[360]; //表示能够达到这个角度
int main()
{
freopen( "in.txt", "r", stin );
int T;
cin >> T;
int k;
string dir;
int angle, toforward, toback;
int d[100];
int index;
while( T-- )
{
cin >> k;
index = 0;
while( k-- )
{
cin >> dir >> angle;
if( dir[0] == 'l' )
d[index++] = 360-angle;
else if( dir[0] == 'r')
d[index++] = angle;
else if( dir[0] == 'f')
toforward += angle;
else
toback += angle;
}
//从d数组中 找出若干个数之和 使其和对 360取模 接近 180
for( int i = 0; i < index; i++ )
{
memset( d, false; sizeof(d) );
for( )
}
}
cout << "Hello world!" << endl;
return 0;
}