上周末去参加了北京大学的ACM赛,10道题目,做出了两道(感觉没脸说)A题和C题,哈哈……先讲讲这两道题吧。
A题:http://poj.openjudge.cn/campus2011/A/
大意是,早锻炼打卡,每学期要打够早锻炼10次,晚锻炼20次。早上7点到9:30为早锻炼时间,晚上必须打卡两次,相隔半个小时,才算一次晚锻炼。打卡时间已经排好序了。
这道题主要考虑的是,一早上不能重复打卡,第二晚上打卡必须超过半小时,晚上重复打卡的情况比较复杂。但是搞清楚逻辑还是可以过得。
代码如下:
#include<stdio.h> #define ONLINE void online() { #ifdef ONLINE #else freopen("acm1.in", "r", stdin); freopen("acm1.out", "w", stdout); #endif } const int MORN = 1; const int HALF = 2; const int morn = 10; const int half = 20; int mnumber = 0; int hnumber = 0; struct Time { int h; int m; int s; int yy; int mm; int dd; }; Time lastt, newt; int lasttype = 0; int istime(Time t) { int type =0; if(t.h == 7) return MORN; if(t.h == 8 && t.m >=0 && t.m <= 30) return MORN; if(t.h >= 16 && t.h < 21) return HALF; if(t.h==21 && t.m>=0 && t.m <= 30) return HALF; return 0; } int main() { online(); //找到第一个合法时间 while(scanf("%d%d%d%d%d%d", &newt.h, &newt.m, &newt.s, &newt.yy,&newt.mm, &newt.dd) != EOF) { int type = istime(newt); if(type == 0) continue; if(type == MORN) { mnumber ++; lasttype = MORN; lastt = newt; break; } if(type == HALF) { lastt = newt; lasttype = HALF; break; } } while(scanf("%d%d%d%d%d%d", &newt.h, &newt.m, &newt.s, &newt.yy,&newt.mm, &newt.dd) != EOF) { int type = istime(newt); if(type == 0) continue; if(type == MORN) { if(lasttype == MORN) { if(newt.yy == lastt.yy && newt.mm == lastt.mm && newt.dd == lastt.dd) { continue; } } mnumber ++; lastt = newt; lasttype = type; } if(type == HALF) { if(lasttype == MORN) { lastt = newt; lasttype = type; continue; } if(lasttype == HALF) { if(newt.yy == lastt.yy && newt.mm == lastt.mm && newt.dd == lastt.dd) { if((newt.m-lastt.m) * 60 + (newt.h - lastt.h)* 3600 + newt.s - lastt.s >= 1800) { hnumber ++; lasttype = 0; continue; }//end if } else { lastt = newt; continue; } } if(lasttype == 0) { if(newt.yy == lastt.yy && newt.mm == lastt.mm && newt.dd == lastt.dd) { lasttype = 0; continue; } else { lastt = newt; lasttype = type; continue; } } } } int mresult = morn - mnumber; int hresult = half - hnumber; if(mresult < 0) mresult = 0; if(hresult < 0) hresult = 0; printf("%d %d", mresult, hresult); return 0; }
当时比较紧张吧,有一些特殊情况没有考虑好,另一方面用例也没有设计好,结果导致了出错的。
C题:http://poj.openjudge.cn/campus2011/C/
大意是一个单词变化到另一个单词的最短步骤吧,这道题让我想到了两个字符串相似度的编辑距离算法。我当时的思路是,计算出两两单词之间通过一次变换可以得到的情况,得到一个记录数组,然后采用最短距离的思想,求出原单词到目标单词的距离。
源代码如下:
#include<stdio.h> #include<string.h> #define ONLINE void online() { #ifdef ONLINE #else freopen("acm3.in", "r", stdin); freopen("acm3.out", "w", stdout); #endif } const int N = 6002; const int SIZE = 100; char start[SIZE]; char end[SIZE]; char lexicon[N][SIZE]; int used[N] = {0}; int len; bool flag = false; bool equal = false; int map[N][N] = {0}; int path[N]; int load[N]; int pl=0; int lenword(int a, int b) { int l1 = strlen(lexicon[a]); int l2 = strlen(lexicon[b]); int change =2; if(l1 == l2) { change= 0; for(int i=0; i < l1; i ++) { if(lexicon[a][i] != lexicon[b][i]) { change ++; }//end if }//end for } if(change >= 2) return 0; if(change == 0) return 2; return 1; } void read() { len = 0; while(scanf("%s", lexicon[len])!= EOF) { for(int i=0; i < len; i ++) { int type = lenword(i, len); if(type == 1) { map[i][len] = 1; map[len][i] = 1; } else if(type == 2 && i == 1) { map[i][len] = 3; map[len][i] = 3; equal = true; } } len ++; } } void ladder() { path[0] = 0; pl = 1; used[0] = 1; load[0] = 0; for(int i=0; i < pl; i ++) { if(flag) break; for(int j=0; j < len; j ++) { if(used[j] == 0 && map[path[i]][j] == 1 && j == 1) { path[pl] = j; load[pl] = load[i] + 2; printf("%d", load[pl]); flag = true; break; } if(used[j] == 0 && map[path[i]][j] == 1) { path[pl] = j; load[pl] = load[i] + 1; used[j] = 1; pl ++; }//end if else if(used[j] == 0 && map[path[i]][j] == 3) { path[pl] = j; load[pl] = load[i] + 1; printf("%d", load[pl]); flag = true; pl ++; break; }//end if } } if(!flag) printf("%d", -1); } int main() { online(); read(); if(equal) ladder(); else printf("%d", -1); return 0; }
最坑爹是J题吧,当时做完这两道题的时候,是12点5分,还有将近两个半小时,当时看到J题的AC最多,其实我原先考虑过一遍,觉得这道题不简单,但是我看着这么多人通过,就冲动了。觉得是不是自己思维错了,又重新考虑了几遍,然后就一头栽进去了。这一进去就是比赛结束。后来出来的时候看到别人的解题报告。“此题可以首先分别扫描三个aspect,然后统计出每个aspect的最小值,再重新扫描一遍每一个team,如果该team的三个aspect都等于最小值,则计数加一,最后输出总的计数即可。复杂度O(n)。” 我发现真是坑爹的。“A team is called "special", if no other team's score is less than it in all three aspects. ”,这句话。。。。。。我不说啥了,我至今觉得仍然那些过了的人都是错误,而我的做法是正确的。
现在想来,自己当时犯得错误有:第一,不管别人做的怎么样,你自己才是最重要的,你不会做,再多的人做出来也没有用。第二,你的思维进入了误区,或者你的理解是对的,在大家都理解错的情况下,你还是要淡定的换一道题目。第三,不管怎么样,一定要把所有的题目都看一遍,我当时就看了这三道题目,其实还是有好几道题目,我是可以搞定的。第四,一个人的作为总是有限的,我在比赛中,缺乏对队友意见的考虑,如果当初他们叫我放弃的时候,我答应了,就不会这样子了。第五,5个小时里面,时间是很有限的,如果一道题没有想法的话,要果断的放弃,千万不要死磕啊。还有一方面的原因,我当时的目标就是做出来3道题,结果把自己给害了。
经验不足啊!下次接着努力吧,估计下次只能一个人去参赛了,他们都说找完工作就不搞了。
自己一个人学习算法,虽然中间走走停停的,前前后后算起来,也有半年时间了,突然间发现自己处于一个很尴尬的位置,难的题目还是搞不出来,简单的题目在大赛中,又是大家磕磕绊绊都能搞出来的,所以即使我很快的搞定前几道题目,最后剩下好几个小时搞后面的题目还是搞不出来,最后成绩还是那样,什么时候我才能接近那种大神的境界啊,那该是何等的快意啊!
这两次比赛的总结就先写到这吧,我觉得我应该去拜师,进一步提升一下自己。