时间:2016.11.27 9:00——12:00
OJ系统:PTA(感谢陈越姥姥提供竞赛平台~)
成绩:144/220(分数/总分)
自我评价:及格,打个分数的话,60%吧......今天状态一直不好,昨晚发烧+失眠......唉 :-(
以下是题目和代码。(做法可能不是最优的,路过的童鞋们多多指教~)
1元5角钱人民币兑换5分、2分和1分的硬币(每一种都要有)共100枚,会有很多种兑换方案。请编写程序给出各种兑换方案。
输入格式:
输入为一个正整数n,表示要求输出前n种可能的方案。方案的顺序,是按照5分硬币从少到多排列的。
输出格式:
显示前n种方案中5分、2分、1分硬币各多少枚。每行显示一种方案,数字之间空一格,最后一个数字后没有空格。
注意:如果全部方案不到n种,就顺序输出全部可能的方案。
输入样例:
5
输出样例:
1 46 53
2 42 56
3 38 59
4 34 62
5 30 65
思路分析:这道题类似于经典的“百钱百鸡”,暴力枚举即可。定义five、two、one分别是5分、2分和1分的硬币,因为每种硬币数量都有且总的数量是100枚,所以三个变量的下限都是1~100之间。把1元5角单位转化成分,即150分,枚举三个变量找到解就输出,退出函数。
Accepted Code:
#include <cstdio>
#define TARGET 1 * 100 + 5 * 10
void solve( int cur ) {
for( int five = cur; five < 100; five++ ) {
for( int two = 1; two < 100; two++ ) {
for( int one = 1; one < 100; one++ ) {
if( ( five * 5 + two * 2 + one ) == TARGET ) {
if( five + two + one == 100 ) {
printf( "%d %d %d\n", five, two, one );
return;
}
}
}
}
}
}
int main() {
int n;
scanf( "%d", &n );
for( int i = 1; i <= n; i++ ) {
solve( i );
}
return 0;
}
请编写程序输出前n个正整数的全排列(n<10),并通过9个测试用例(即n从1到9)观察n逐步增大时程序的运行时间。
输入格式:
输入给出正整数n(<10)。
输出格式:
输出1到n的全排列。每种排列占一行,数字间无空格。排列的输出顺序为字典序,即序列a1,a2,⋯,an排在序列b1,b2,⋯,bn之前,如果存在k使得a1=b1,⋯,ak=bk 并且 ak+1<bk+1。
输入样例:
3
输出样例:
123
132
213
231
312
321
思路分析:很直白问你全排列。C++有写好的next_permutation函数,直接拿过来用就行。也可以自己写个DFS。用Java的童鞋就比较悲催了,不仅要自己写DFS还要考虑超时的问题......
Accepted Code:
#include <cstdio>
#include <algorithm>
#define MAX 10
using namespace std;
int a[MAX];
int b[MAX];
int visit[MAX];
void Print( int n ) {
for( int i = 0; i < n; i++ ) {
printf( "%d", a[i] );
}
printf( "\n" );
}
// DFS全排列,不要数组a,b也行,我这里写有点麻烦了
// cur是已经选择数字的数量
// n是需要的数字数量,递归出口
void dfs( int cur, int n ) {
if( cur == n ) {
for( int i = 0; i < n; i++ ) {
printf( "%d", b[i] );
}
printf( "\n" );
return;
}
for( int i = 0; i < n; i++ ) {
if( !visit[i] ) {
visit[i] = 1;
b[cur] = a[i];
dfs( cur + 1, n );
visit[i] = 0; // 回溯
}
}
}
int main() {
int n;
scanf( "%d", &n );
for( int i = 0; i < n; i++ ) {
a[i] = i + 1;
}
// 把注释去掉用这个也可以
/*
do {
Print( n );
} while( next_permutation( a, a + n ) );
*/
dfs( 0, n );
return 0;
}
符号配对 (20分)
请编写程序检查C语言源程序中下列符号是否配对:/*
与*/
、(
与)
、[
与]
、{
与}
。
输入格式:
输入为一个C语言源程序。当读到某一行中只有一个句点.
和一个回车的时候,标志着输入结束。程序中需要检查配对的符号不超过100个。
输出格式:
首先,如果所有符号配对正确,则在第一行中输出YES
,否则输出NO
。然后在第二行中指出第一个不配对的符号:如果缺少左符号,则输出?-右符号
;如果缺少右符号,则输出左符号-?
。
输入样例1:
void test()
{
int i, A[10];
for (i=0; i<10; i++) /*/
A[i] = i;
}
.
输出样例1:
NO
/*-?
输入样例2:
void test()
{
int i, A[10];
for (i=0; i<10; i++) /**/
A[i] = i;
}]
.
输出样例2:
NO
?-]
输入样例3:
void test()
{
int i
double A[10];
for (i=0; i<10; i++) /**/
A[i] = 0.1*i;
}
.
输出样例3:
YES
思路分析:这道题没AC(拿了16分,一个测试点没过)。经典的使用栈的问题。策略是遇到 /* ( [ { ,进行压栈,遇到*/ ) ] } 就与栈顶元素进行判断,如果相同就执行弹栈,不相同说明格式是有问题的。这种策略是正确的,因为最近匹配的原因,位于栈顶的元素肯定是最近一次的符号。这道题没AC,多半原因是/*和*/的问题。
16分 Code:
#include <cstdio>
#include <stack>
#include <string>
#include <iostream>
using namespace std;
int main() {
//freopen( "123.txt", "r", stdin );
string input;
stack<string> s;
string ans;
bool flag = true;
while( 1 ) {
getline( cin, input );
if( input == "." || input == "\r" ) break;
for( int i = 0; i < input.size(); i++ ) {
if( input[i] == '(' ) s.push( "(" );
if( input[i] == '[' ) s.push( "[" );
if( input[i] == '{' ) s.push( "{" );
if( ( input[i] == '/' && input[i + 1] == '*' ) || ( input[i] == '/' ) ) {
s.push( "/*" );
}
string top;
if( s.empty() ) top = "####";
else top = s.top();
// left not
if( input[i] == ')' ) {
if( top == "(" ) s.pop();
else {
flag = false;
ans = "?-)";
}
}
if( input[i] == ']' ) {
if( top == "[" ) s.pop();
else {
flag = false;
ans = "?-]";
}
}
if( input[i] == '}' ) {
if( top == "{" ) s.pop();
else {
flag = false;
ans = "?-}";
}
}
if( ( input[i] == '*' && input[i + 1] == '/' ) || ( input[i] == '/' ) ) {
if( top == "/*" ) s.pop();
else {
flag = false;
ans = "?-*/";
}
}
if( !flag ) break;
}
}
if( !s.empty() ) {
ans = s.top();
ans = ans + "-?";
flag = false;
}
if( flag ) {
cout << "YES" << endl;
}
else {
cout << "NO" << endl;
cout << ans << endl;
}
return 0;
}
两个有序序列的中位数 (25分)
已知有两个等长的非降序序列S1, S2, 设计函数求S1与S2并集的中位数。有序序列A0,A1,⋯,AN−1的中位数指A(N−1)/2的值,即第⌊(N+1)/2⌋个数(A0为第1个数)。
输入格式:
输入分三行。第一行给出序列的公共长度N(0<N≤100000),随后每行输入一个序列的信息,即N个非降序排列的整数。数字用空格间隔。
输出格式:
在一行中输出两个输入序列的并集序列的中位数。
输入样例1:
5
1 3 5 7 9
2 3 4 5 6
输出样例1:
4
输入样例2:
6
-100 -10 1 1 1 1
-50 0 2 3 4 5
思路分析:我认为这道题题意描述不清,当时赛场上调试了不少时间。题意中说两个序列的并集,我很快想到了用set,处理两个集合的并集,并找到中位数。然而提交WA,一个测试点没过。没想到是我想多了......直接合并两个序列(不去重,而两个集合的合并是去重的),排序找到中位数就OK。LeetCode上有很多类似的题,有更高效的做法。我的做法简单粗暴,也能AC~
Accepted Code:
#include <cstdio>
#include <algorithm>
#define MAX 100000 + 10
using namespace std;
int a[MAX];
int main() {
int n;
scanf( "%d", &n );
for( int i = 0; i < 2 * n; i++ ) {
scanf( "%d", &a[i] );
}
sort( a, a + 2 * n );
printf( "%d\n", a[( 2 * n - 1 ) / 2] );
return 0;
}
英文单词排序 (25分)
本题要求编写程序,输入若干英文单词,对这些单词按长度从小到大排序后输出。如果长度相同,按照输入的顺序不变。
输入格式:
输入为若干英文单词,每行一个,以#
作为输入结束标志。其中英文单词总数不超过20个,英文单词为长度小于10的仅由小写英文字母组成的字符串。
输出格式:
输出为排序后的结果,每个单词后面都额外输出一个空格。
输入样例:
blue
red
yellow
green
purple
#
输出样例:
red blue green yellow purple
思路分析:亲爱的亲爱的,这道题为什么要用散列呢?显然是考排序呀~更准确的说是多标尺排序。第一标尺是单词长度,第二标尺是输入顺序。我的做题习惯是遇到这种多标尺排序问题,定义一个结构体存储信息,里边就是数据和标尺了。然后重写sort中的cmp函数就行,调用sort就可以了。注意输出格式,每个单词后面都有一个空格。
Accepted Code:
#include <iostream>
#include <string>
#include <algorithm>
#define MAX 20 + 10
using namespace std;
typedef struct {
string str;
int rank; // 输入顺序
} STR;
STR str[MAX];
int cmp( STR a, STR b ) {
int aLen = a.str.size();
int bLen = b.str.size();
// 判断第一标尺
if( aLen != bLen ) {
return aLen < bLen ? 1 : 0;
}
// 相同判断输入顺序
return a.rank < b.rank ? 1 : 0;
}
int main() {
string input;
int i = 0;
while( 1 ) {
cin >> input;
if( input == "#" ) {
break;
}
else {
str[i].str = input;
str[i].rank = i; // rank记录输入顺序
i++;
}
}
sort( str, str + i, cmp );
for( int j = 0; j < i; j++ ) {
cout << str[j].str << " ";
}
return 0;
}
哥尼斯堡的“七桥问题” (25分)
哥尼斯堡是位于普累格河上的一座城市,它包含两个岛屿及连接它们的七座桥,如下图所示。
可否走过这样的七座桥,而且每桥只走过一次?瑞士数学家欧拉(Leonhard Euler,1707—1783)最终解决了这个问题,并由此创立了拓扑学。
这个问题如今可以描述为判断欧拉回路是否存在的问题。欧拉回路是指不令笔离开纸面,可画过图中每条边仅一次,且可以回到起点的一条回路。现给定一个无向图,问是否存在欧拉回路?
输入格式:
输入第一行给出两个正整数,分别是节点数N (1≤N≤1000)和边数M;随后的M行对应M条边,每行给出一对正整数,分别是该条边直接连通的两个节点的编号(节点从1到N编号)。
输出格式:
若欧拉回路存在则输出1,否则输出0。
输入样例1:
6 10
1 2
2 3
3 1
4 5
5 6
6 4
1 4
1 6
3 4
3 6
输出样例1:
1
输入样例2:
5 8
1 2
1 3
2 3
2 4
2 5
5 3
5 4
3 4
输出样例2:
0
思路分析:欧拉回路问题,也就是小时候经常玩的一笔画问题。以前没研究过欧拉回路的问题......考场上花了点时间,最终拿了23分,没AC,好可惜......
因为要判断回路,我第一想法是拓扑排序,很快写好拓扑,提交WA,得了21分。然后又想了想用DFS访问边权,并删除掉访问过的边,防止回头。结果还是WA......然后又想着用并查集,很快写好并查集发现这并没什么用......最后DFS+TopSort一起上,DFS判断是否访问所有边,拓扑判断是否回路,拿了23分,最后一个case运行超时。
其实判断欧拉回路很简单:如果图中每个点的度是偶数,并且图是连通的,就是欧拉回路了......看来图的一些性质我还需要了解。
Accepted Code:
#include <cstdio>
#define MAX 1000 + 10
int MGraph[MAX][MAX];
int degree[MAX];
int visit[MAX];
void dfs( int v, int n ) {
for( int i = 1; i <= n; i++ ) {
if( !visit[i] && MGraph[v][i] != 0 ) {
visit[i] = 1;
dfs( i, n );
}
}
}
int main() {
int n, m;
scanf( "%d%d", &n, &m );
int a, b;
for( int i = 0; i < m; i++ ) {
scanf( "%d%d", &a, &b );
MGraph[a][b] = 1;
MGraph[b][a] = 1;
degree[a]++;
degree[b]++;
}
int cnt = 0;
for( int i = 1; i <= n; i++ ) {
if( !visit[i] ) {
dfs( i, n ); // dfs计算连通块的数量,如果是1则图中所有点在一个连通块中
cnt++;
}
}
bool flag = true;
if( cnt != 1 ) {
flag = false;
}
// 判断所有点的度是否为偶数
for( int i = 1; i <= n; i++ ) {
if( degree[i] % 2 != 0 ) {
flag = false;
break;
}
}
if( flag ) {
printf( "1\n" );
}
else {
printf( "0\n" );
}
return 0;
}
新浪微博热门话题 (30分)
新浪微博可以在发言中嵌入“话题”,即将发言中的话题文字写在一对“#”之间,就可以生成话题链接,点击链接可以看到有多少人在跟自己讨论相同或者相似的话题。新浪微博还会随时更新热门话题列表,并将最热门的话题放在醒目的位置推荐大家关注。
本题目要求实现一个简化的热门话题推荐功能,从大量英文(因为中文分词处理比较麻烦)微博中解析出话题,找出被最多条微博提到的话题。
输入格式:
输入说明:输入首先给出一个正整数N(≤105),随后N行,每行给出一条英文微博,其长度不超过140个字符。任何包含在一对最近的#
中的内容均被认为是一个话题,如果长度超过40个字符,则只保留前40个字符。输入保证#
成对出现。
输出格式:
第一行输出被最多条微博提到的话题,第二行输出其被提到的微博条数。如果这样的话题不唯一,则输出按字母序最小的话题,并在第三行输出And
k more ...
,其中k
是另外几条热门话题的条数。输入保证至少存在一条话题。
输入样例:
4
This is a #test of topic#.
Another #Test of topic.#
This is a #Hot# #Hot# topic
Another #hot!# #Hot# topic
输出样例:
Hot
2
And 1 more ...
思路分析:读了题目,描述是看懂了,就是样例看不懂,尤其那句And k more......是怎么判断的???网上查别人的题解,也没人AC,估计是题目有问题吧。这里说下大概的方法:
1.首先处理输入问题,因为有空格,所以按行输入处理。C\C++中可以使用gets()或getline( cin, string )处理输入有空格的问题。
2.筛选出每行##之间的字符串,先判断这个字符串是否存在,方法可以用map记录已存在的字符串。不存在,就存到map中,存在记录数加1。注意这里的记录数加1不是这个字符串出现一次就加1,而是如果它在一条微博中出现过,则只能加1。例如第三行Hot出现了两次,Hot出现的次数只能加1,不能加2,因为他俩都在同一条微博中。
3.第2步就涉及到查找是否存在的问题,根据我的尝试直接使用map.find()搜索最后一个case超时,这就需要使用散列了。可以再开一个map记录每个字符串的id,id一定要是唯一的。或者根据字符串进行字符散列映射(链式分离法),不过这样有些复杂了。理论上再开一个map会更方便,应该能AC。
Code:无,gg
地下迷宫探索 (30分)
地道战是在抗日战争时期,在华北平原上抗日军民利用地道打击日本侵略者的作战方式。地道网是房连房、街连街、村连村的地下工事,如下图所示。
我们在回顾前辈们艰苦卓绝的战争生活的同时,真心钦佩他们的聪明才智。在现在和平发展的年代,对多数人来说,探索地下通道或许只是一种娱乐或者益智的游戏。本实验案例以探索地下通道迷宫作为内容。
假设有一个地下通道迷宫,它的通道都是直的,而通道所有交叉点(包括通道的端点)上都有一盏灯和一个开关。请问你如何从某个起点开始在迷宫中点亮所有的灯并回到起点?
输入格式:
输入第一行给出三个正整数,分别表示地下迷宫的节点数N(1<N≤1000,表示通道所有交叉点和端点)、边数M(≤3000,表示通道数)和探索起始节点编号S(节点从1到N编号)。随后的M行对应M条边(通道),每行给出一对正整数,分别是该条边直接连通的两个节点的编号。
输出格式:
若可以点亮所有节点的灯,则输出从S开始并以S结束的包含所有节点的序列,序列中相邻的节点一定有边(通道);否则虽然不能点亮所有节点的灯,但还是输出点亮部分灯的节点序列,最后输出0,此时表示迷宫不是连通图。
由于深度优先遍历的节点序列是不唯一的,为了使得输出具有唯一的结果,我们约定以节点小编号优先的次序访问(点灯)。在点亮所有可以点亮的灯后,以原路返回的方式回到起点。
输入样例1:
6 8 1
1 2
2 3
3 4
4 5
5 6
6 4
3 6
1 5
输出样例1:
1 2 3 4 5 6 5 4 3 2 1
输入样例2:
6 6 6
1 2
1 3
2 3
5 4
6 5
6 4
输出样例2:
6 4 5 4 6 0
思路分析:一拿到这个题很开心呀,显然用DFS深搜,很快写好代码,提交WA,两个测试点错误......纠结了半个小时,找不出问题......
我的想法是这样的:从起点开始进行DFS,一直搜索,不回头。这样走到死胡同就无路可走了,DFS退出,把走过的路径记录到vector或数组或stack中,先正着打印一遍,再反向打印一遍,就相当于沿原路返回到起点。如果访问不了所有结点再额外打印一个0,为什么我提交WA呢?策略有问题吗?
网上搜了下别人的题解,和我想法不同的地方就是DFS的时候并添加返回路径,相当于在我的DFS基础上添加一行代码就OK。然后打印路径直接按顺序打印,不用反向打印。这种策略能AC。
我感觉一样的呀,,为什么我的不对呢,如果有路过的童鞋们明白帮我解答一下,感激不尽~~~
先上我的代码:
20分 Code
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
#include <queue>
#include <cstdio>
#define MAX 3000 + 10
#define INF 0x3fffffff
using namespace std;
int MGraph[MAX][MAX];
int visit[MAX];
int n, m;
int S;
int cnt;
vector<int> vec;
void initMGraph() {
for( int i = 0; i < MAX; i++ ) {
for( int j = 0; j < MAX; j++ ) {
MGraph[i][j] = 0;
}
}
}
// 一直深搜,不回头
void dfs( int cur ) {
visit[cur] = 1;
vec.push_back( cur );
//cnt++;
for( int i = 1; i <= n; i++ ) {
if( !visit[i] && MGraph[cur][i] != 0 ) {
dfs( i );
//vec.push_back( cur );
//cnt++;
}
}
}
int main() {
initMGraph();
//freopen( "123.txt", "r", stdin );
scanf( "%d%d%d", &n, &m, &S );
int a, b;
for( int i = 0; i < m; i++ ) {
scanf( "%d%d", &a ,&b );
MGraph[a][b] = 1;
MGraph[b][a] = 1;
}
//vec.push_back( S );
//visit[S] = 1;
//cnt = 1;
dfs( S );
bool flag = true;
// 判断是否所有点都访问过了
//if( cnt < n ) flag = false;
for( int i = 1; i <= n; i++ ) {
if( visit[i] == 0 ) {
flag = false;
break;
}
}
// 先正着打印一次路径,再反向打印一次
if( flag ) {
for( int i = 0; i < vec.size(); i++ ) {
if( i == 0 ) printf( "%d", vec[i] );
else printf( " %d", vec[i] );
}
for( int i = vec.size() - 2; i >= 0; i-- ) {
printf( " %d", vec[i] );
}
}
else {
for( int i = 0; i < vec.size(); i++ ) {
if( i == 0 ) printf( "%d", vec[i] );
else printf( " %d",vec[i] );
}
for( int i = vec.size() - 2; i >= 0; i-- ) {
printf( " %d", vec[i] );
}
printf( " 0" );
}
return 0;
}
再贴上AC代码:
Accepted Code:
#include <algorithm>
#include <string>
#include <vector>
#include <iostream>
#include <queue>
#include <cstdio>
#define MAX 3000 + 10
#define INF 0x3fffffff
using namespace std;
int MGraph[MAX][MAX];
int visit[MAX];
int n, m;
int S;
int cnt;
vector<int> vec;
void initMGraph() {
for( int i = 0; i < MAX; i++ ) {
for( int j = 0; j < MAX; j++ ) {
MGraph[i][j] = 0;
}
}
}
// 一直深搜,不回头
void dfs( int cur ) {
visit[cur] = 1;
vec.push_back( cur );
//cnt++;
for( int i = 1; i <= n; i++ ) {
if( !visit[i] && MGraph[cur][i] != 0 ) {
dfs( i );
vec.push_back( cur );
//cnt++;
}
}
}
int main() {
initMGraph();
//freopen( "123.txt", "r", stdin );
scanf( "%d%d%d", &n, &m, &S );
int a, b;
for( int i = 0; i < m; i++ ) {
scanf( "%d%d", &a ,&b );
MGraph[a][b] = 1;
MGraph[b][a] = 1;
}
//vec.push_back( S );
//visit[S] = 1;
//cnt = 1;
dfs( S );
bool flag = true;
for( int i = 1; i <= n; i++ ) {
if( visit[i] == 0 ) {
flag = false;
break;
}
}
if( flag ) {
for( int i = 0; i < vec.size(); i++ ) {
if( i == 0 ) printf( "%d", vec[i] );
else printf( " %d", vec[i] );
}
}
else {
for( int i = 0; i < vec.size(); i++ ) {
printf( "%d ", vec[i] );
}
printf( "0" );
}
return 0;
}
长城 (30分)
正如我们所知,中国古代长城的建造是为了抵御外敌入侵。在长城上,建造了许多烽火台。每个烽火台都监视着一个特定的地区范围。一旦某个地区有外敌入侵,值守在对应烽火台上的士兵就会将敌情通报给周围的烽火台,并迅速接力地传递到总部。
现在如图1所示,若水平为南北方向、垂直为海拔高度方向,假设长城就是依次相联的一系列线段,而且在此范围内的任一垂直线与这些线段有且仅有唯一的交点。
图 1
进一步地,假设烽火台只能建造在线段的端点处。我们认为烽火台本身是没有高度的,每个烽火台只负责向北方(图1中向左)瞭望,而且一旦有外敌入侵,只要敌人与烽火台之间未被山体遮挡,哨兵就会立即察觉。当然,按照这一军规,对于南侧的敌情各烽火台并不负责任。一旦哨兵发现敌情,他就会立即以狼烟或烽火的形式,向其南方的烽火台传递警报,直到位于最南侧的总部。
以图2中的长城为例,负责守卫的四个烽火台用蓝白圆点示意,最南侧的总部用红色圆点示意。如果红色星形标示的地方出现敌情,将被哨兵们发现并沿红色折线将警报传递到总部。当然,就这个例子而言只需两个烽火台的协作,但其他位置的敌情可能需要更多。
然而反过来,即便这里的4个烽火台全部参与,依然有不能覆盖的(黄色)区域。
图 2
另外,为避免歧义,我们在这里约定,与某个烽火台的视线刚好相切的区域都认为可以被该烽火台所监视。以图3中的长城为例,若A、B、C、D点均共线,且在D点设置一处烽火台,则A、B、C以及线段BC上的任何一点都在该烽火台的监视范围之内。
图 3
好了,倘若你是秦始皇的太尉,为不致出现更多孟姜女式的悲剧,如何在保证长城安全的前提下,使消耗的民力(建造的烽火台)最少呢?
输入格式:
输入在第一行给出一个正整数N
(3 ≤ N
≤105),即刻画长城边缘的折线顶点(含起点和终点)数。随后N
行,每行给出一个顶点的x
和y
坐标,其间以空格分隔。注意顶点从南到北依次给出,第一个顶点为总部所在位置。坐标为区间[−109,109)内的整数,且没有重合点。
输出格式:
在一行中输出所需建造烽火台(不含总部)的最少数目。
输入样例:
10
67 32
48 -49
32 53
22 -44
19 22
11 40
10 -65
-1 -23
-3 31
-7 59
输出样例:
2
这道题压根没看......我一直以为是上次天体赛决赛最后一题,那道题是考查凸包,暂时不会这个知识点,而且上次决赛最后一题也没人拿满,就干脆放弃了。天呐呐呐,结果是我记错了,凸包那个题是“水果忍者”,这道题是初赛的最后一题,当时也没几个人AC......所以,,干脆就不看了吧。
总结:除了微博那道题有点问题,还有最后一道压根没考虑做之外,剩下最多就能答160分了。遗憾的是欧拉回路和地宫搜索那两道没AC,着实可惜......再过10天又要上战场了,好担心......再好好复习一下!