USACO算法系列——北大ACM(番外篇)

    为了参加周末北大举行的比赛,特意上北大ACM网站做了几道题。北大的有道算法比赛,还真是难啊,估计只能去打酱油了。唉,现在USACO还差最后的10题。希望能在这周和下周完成吧,完成了也算是做完了一件事。

    讲讲今天在北大做的那几道题吧。

    第一题1000,a + b. 没什么好说的,只是为了让大家熟悉一下这个平台。像我这种不熟悉平台,上来就直接敲代码的,第一次提交自然是OVER的。那里的提交不是直接读写文件,而是直接读取流,为了便于调式,用宏定义,写了一个online的开关。但是提交的时候,好几次忘了关了,然后悲剧了,唉。。。。有利有弊吧。

#include <stdio.h> #define ONLINE_JUDGE int a, b; void read() { #ifdef ONLINE_JUDGE #else freopen("ab.in", "r", stdin); freopen("ab.out", "w", stdout); #endif scanf("%d%d", &a, &b); } int main() { read(); printf("%d", a+b); return 0; }

   第二道题1001,Exponentiation,就一个浮点数R的N次方。其实就是大整数乘法。首先为了便于计算可以把它转化为科学计数法,即整数M* 10的K次方的形式,根据取值范围为0-99.999,即0-100000,N的取值为0-25.因此大整数的长度为150位。

#include<stdio.h> #include <string.h> #define ONLINE #define SIZE 200 char cr[SIZE]; int n; int number[SIZE] = {0}; int nl = 0; int digit =0; int result[SIZE] = {0}; int rl = 0; void online() { #ifdef ONLINE #else freopen("Exponentiation.in", "r", stdin ); freopen("Exponentiation.out", "w", stdout); #endif } void init() { int len = strlen(cr); nl = 0; digit = 0; for (int i=0; i < len; i ++) { if (cr[i] != '.') { number[nl] = cr[i] - '0'; nl ++; } else { digit = len - i - 1; } } for (int i=0; i < nl/2; i ++) { int temp = number[i]; number[i]= number[nl - i-1]; number[nl-i-1] = temp; } rl = nl; for (int i=0; i< nl; i ++) { result[i] = number[i]; } } void pow() { int temp[SIZE] = {0}; int i, j, k; for (i=1; i < n; i ++) { for ( j=0; j < rl; j ++ ) { for ( k =0; k < nl; k ++ ) { temp[j+k] += result[j] * number[k]; temp[j+k+1] += temp[j+k] / 10; temp[j+k] %= 10; }//end for k }//end j if (temp[j+k+1] != 0) { rl = j +k +1; } else { rl = j + k; } for (int m = 0; m < rl ; m ++) { result[m] = temp[m]; } memset(temp, 0, sizeof(int) * SIZE); } } void print() { digit *= n; bool flag = false; for (int i=rl-1; i >=digit; i --) { if (result[i] != 0 || flag == true) { printf("%d", result[i]); flag = true; } } int end =0; for (end =0; end < digit;end++) { if (result[end]!=0) { break; } } if (!flag && digit > end) { printf("."); } else if (digit > end) { printf("."); } else if (!flag) { printf("0"); } for (int i=digit-1; i>=end; i --) { printf("%d", result[i]); } printf("/n"); } int main() { online(); while (scanf("%s%d", cr, &n) != EOF) { init(); pow(); print(); } return 0; }

   第三题:1002,487-3279。求正确的电话号码的格式,并且这个号码超过1次。我使用的Tri树的方法,结果空间跟其他人相比好像有点大,我觉得也可以使用HASH散列的方法。有空去实现一下吧

#include <stdio.h> #include <string.h> #define ONLINE #define SIZE 100 int cas = 0; char phone[SIZE]; char number[26] = {2,2,2,3,3,3,4,4,4,5,5,5,6,6,6,7,-1,7,7,8,8,8,9,9,9,-1}; int pn[8]; int pl =0; struct SPhone { SPhone * p[10]; int n; }; SPhone sp; bool flag = false; void online() { #ifdef ONLINE #else freopen("phone.in","r", stdin); freopen("phone.out", "w", stdout); #endif } void print(SPhone * tp, int level) { if (level == 7) { if (tp->n <= 1) { return; } flag = true; for (int i=0; i < 7; i ++) { printf("%d", pn[i]); if (i == 2) { printf("-"); } } printf(" %d/n", tp->n); return; } for (int i=0; i < 10; i ++) { if (tp->p[i] != NULL) { pn[level] = i; print(tp->p[i], level+1); } } } void add() { SPhone *temp = &sp; for (int i=0; i < 7; i ++) { if (temp->p[pn[i]] == NULL) { temp->p[pn[i]] = new SPhone(); temp->p[pn[i]]->n = 0; } temp = temp->p[pn[i]]; } temp->n ++; } void consult() { int len = strlen(phone); pl =0; for (int i=0; i < len; i ++) { if (phone[i] == '-') { continue; } else if (phone[i] == 'Q' || phone[i] == 'Z') { return; } else if (phone[i] >= '0' && phone[i] <= '9') { if (pl >= 7) { return; } pn[pl] = phone[i] - '0'; pl ++; } else if (phone[i] >= 'A' && phone[i] <= 'Z') { if (pl >= 7) { return; } pn[pl] = number[phone[i]-'A']; pl ++; } else return; } add(); } void read() { scanf("%d", &cas); for (int i=0; i < cas; i ++) { scanf("%s", phone); consult(); } } int main() { online(); read(); print(&sp, 0); if (flag == false) { printf("No duplicates. "); } return 0; }

   第四题:1003,Hangover。题目读懂了以后,就知道实际上是求(1/2 + 1/3 + ..... +1/n) > st的n-2的值。所以也不难吧。

#include<stdio.h> #define ONLINE void online() { #ifdef ONLINE #else freopen("Hangover.in", "r", stdin); freopen("Hangover.out", "w", stdout); #endif } float n; void read() { while (scanf("%f", &n) != EOF) { double st = 0.0; int j = 2; while(st < n) { st += 1.0 / j; j ++; } if (n>0.0) { printf("%d card(s)/n", j-2); } } } int main() { online(); read(); return 0; }

   发现ACM每提交错误一次,加20分钟,这个可真是一个bug,所以提交时,肯定要保证时间的准确性。

你可能感兴趣的:(USACO算法系列——北大ACM(番外篇))