http://hihocoder.com/contest/hiho59/problem/1
题意分析
给定一个单线程程序运行的记录,包含有每个函数启动和结束的时间。判定该份记录是否错误,主要的错误包含:
记录中的时间不是严格递增的
一个函数的结束时间比启动时间更早
记录中一个函数有不对应的启动操作START或结束操作END,比如出现了START却没有对应的END,或出现了END却没有出现START。而函数的START和END应该成对出现
两个函数出现交叉的情况,而在单线程程序中是不会出现的,比如 A START B START A END B END
算法分析
根据上面对可能出现错误的分析,我们可以分别对每一种错误进行处理:
记录中的时间不是单调递增的
对每一条记录的时间都与前一条的时间进行比较即可判定。
一个函数的结束时间比启动时间更早
对出现的START和END标记的时间直接进行计算即可判定。
不对应的START和END
统计每个函数START和END的个数是否相等即可判定
两个函数出现交叉
本题要做的是模拟一个函数调用栈,其实际考察的内容是对于栈的理解和运用。
我们将函数启动的操作视为进栈PUSH,函数结束的操作视为出栈POP,对于一个单线程的程序来说,其函数的调用一定满足栈的过程。在出现函数A中调用函数B的情况时,函数B的结束时间一定早于函数A。这正是栈过程中先进后出原则的体现。
如果我们用栈来模拟前面的例子,则有
A START
Stack A
B START
Stack A B
A END
此时出现了错误,其操作为不在栈顶的A出栈。
对于正确的情况,比如:
A START B START B END A END
同样用栈来模拟时有:
A START
Stack A
B START
Stack A B
B END
Stack A
A END
Stack
因此对于第三类错误,我们需要在程序中使用栈来模拟整个过程,即可判定是否有出现错误。
总结
我们使用栈来模拟整个程序调用的过程:
首先对于每一个记录比较与前一条记录的时间。
当出现了START操作的函数直接进栈。
当出现了END操作的函数时,判定该函数是否就是栈顶的函数,若不是则表明该记录有错误。同时对于第二类操作中"出现了END却没有出现START"的情况也处理了。若出栈元素是栈顶元素时,我们在此时对其时间进行一次检查,就可以判定第一类错误。
当整个过程记录都使用栈模拟完毕后,我们还需要对当前栈内是否还有元素进行判定。若栈不为空,则出现第二类情况中"出现了START却没有对应的END"的情况。
此外在输出时,题目要求按照函数调用树深度优先的顺序依次输出每一个函数。在模拟栈的过程中,函数入栈的顺序也正是调用树的顺序,所以在处理过程中我们使用一个序列outputList来记录函数入栈的顺序,并在函数END操作时去更新该函数其运行时间。
其伪代码如下:
For i = 1 .. n
If (i != 0 and log[i].time < log[i - 1].time)
Return "Error"
End If
If log[i].Action == "START" Then
Stack.Push(log[i])
outputList.push(log[i].FuncName) // 将该函数压入输出序列
Else
If (Stack.Size == 0 or Stack.Top.FuncName != log[i].FuncName)
Return "Error"
End If
startLog = Stack.Pop()
If startLog.Time > log[i].Time Then
Return "Error"
End If
setTime(startLog.FuncName, log[i].Time - startLog.Time)
// 记录outputList中名称为startLog.FuncName的函数的运行时间
End If
End For
结果分析
在实际的比赛中,该题目的通过率为14%。
在选手的程序中主要出现的错误有:
由于本题涉及了时间格式,在时间输入输出上出现问题,导致时间计算出问题
未判定函数开始时间是否大于结束时间
模拟栈结束后未检查栈是否为空,很多选手都是因为这个原因而没有得到100分
一开始想到了用栈模拟递归,但是没想到的是开始时间居然可以等于结束时间,错了好几发 -_-|||
还有一句感慨:C++真是一个面向对象的语言啊
AC代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int Mod = 1e9 + 7;
const int maxn = 1e5 + 5;
const double eps = 0.00000001;
const int INF = 0x3f3f3f3f;
struct Log{
int hh, mm, ss;
LL sum;
int id;
string fName;
void init() {
sum = 0;
}
void ms() {
sum = hh * 3600 + mm * 60 + ss;
}
void fms() {
LL tt = sum;
hh = tt/3600;
tt %= 3600;
mm = tt/60;
tt %= 60;
ss = tt;
}
void print() {
this->fms();
cout << this->fName;
printf(" %02d:%02d:%02d\n", this->hh, this->mm, this->ss);
}
};
map<string, int> mp;
string str[maxn];
Log Sta[maxn], st[maxn];
int top = 0, cnt = 0, c[maxn];
bool vis = false;
int main()
{
int T;
cin >> T;
memset(c, 0, sizeof(c));
while(T --) {
string fun, time, op;
cin >> fun >> time >> op;
if(vis) continue;
Log tmp;
tmp.fName = fun;
tmp.hh = (time[0] - '0') * 10 + (time[1] - '0');
tmp.mm = (time[3] - '0') * 10 + (time[4] - '0');
tmp.ss = (time[6] - '0') * 10 + (time[7] - '0');
tmp.ms();
if(!mp[tmp.fName]) {
mp[tmp.fName] = ++ cnt;
st[cnt].fName = tmp.fName;
st[cnt].init();
}
tmp.id = mp[tmp.fName];
if(op == "END") {
if(Sta[top].id == tmp.id) {
if(tmp.sum >= Sta[top].sum) {
c[tmp.id] --;
tmp.sum = tmp.sum - Sta[top].sum;
st[tmp.id].sum += tmp.sum;
top --;
}else vis = true;
}else vis = true;
}else {
if(c[tmp.id]) vis = true;
else {
if(top) {
if(tmp.sum >= Sta[top].sum) {
c[tmp.id] ++;
Sta[++top] = tmp;
}else vis = true;
}else {
c[tmp.id] ++;
Sta[++top] = tmp;
}
}
}
}
if(top) vis = true;
if(vis) cout << "Incorrect performance log\n";
else {
for (int i = 1; i <= cnt; i ++)
st[i].print();
}
return 0;
}