20111130

小強歷險記

題目出自DS課本第二章,滿有意思的一題。

題目

一隻喝醉酒的小強在地板上爬來爬去,
假設地板面積為row * col。
假設小強的起始位置為座標(i, j),
小強一次可以移動一格。
小強可以從他現在所待的格子,
移動到周遭其他格子,且機率相等。
請問小強爬過每塊面積至少一次,
需要花多久時間?
輸出總步數與每塊格子經過的次數。

分析

算是一題模擬題。
首先要知道地板的大小,
意即maxrow跟maxcol要定出來。
接著要知道起始點row, col。
從起始點開始往周遭移動,
我們還需要隨機函式與移動方式。
小強從自身待的格子移動到周遭至多有八格。
(八格就是八種情況)
需要考慮邊界問題,與上界問題。
邊界表示,小強移動只能在地板中,不能移動到地板之外;
上界表示,一個格子至多經過x次,超過x次就不能再進入格子。
(這個動作確保有解,程式才得以終止。)
課本提供一種很好的移動資料結構:利用陣列。
假設移動的row座標為mover,
移動的col座標為movec。
小強可以移動到左上,上,右上,右,右下,下,左下,左。
看出來了嗎!
一個點對應一組mover跟movec。
所以mover與movec的內容分別是:
mover[8] = {1, 1, 1, 0, -1, -1, -1, 0};
movec[8] = {-1, 0, 1, 1, 1, 0, -1, -1};
至於要怎麼移動呢?
row = i + mover[j]
col = j + movec[j]
j從0到7為止。
如此配合隨機函式,可以隨機得到一個數字,
介於0到7,得到row與col後,再考慮邊界問題,

若在編界之內,且經過該格子的次數小於x就移動到(row, col)。

到小強每塊格子都經過至少一次時,
就可以輸出總步數與格子的經過情況數。

如果可以用顏色深淺代表移動次數那一定更好玩 XD。

實做程式碼

/* DS ch 2.9 exercise 9
 * mythnc
 * 2011/11/29 10:56:04   
 */
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define ROW   40
#define COL   20
#define FALSE 0
#define TRUE  1
#define MAXT  50000

typedef struct point {
    int x;
    int y;
} Point;

void move(Point, int (*)[], int, int);
int terminal(int (*)[], int, int);
void printout(int (*)[], int, int);

int totalmove = 1;

int main(void)
{
    int square[ROW][COL] = { 0 };
    int maxrow, maxcol;
    Point start;

    printf("max row and col: ");
    scanf("%d %d", &maxrow, &maxcol);
    getchar();
    printf("start point (x, y): ");
    scanf("%d %d", &start.x, &start.y);
    getchar();

    move(start, square, maxrow, maxcol);

    system("clear");
    printout(square, maxrow, maxcol);

    return 0;
}

/* move: cockroach move simulation */
void move(Point start, int (*s)[COL], int maxr, int maxc)
{
    int xmove[] = {1, 1, 1, 0, -1, -1, -1, 0};
    int ymove[] = {-1, 0, 1, 1, 1, 0, -1, -1};
    int i, x, y;

    srand((unsigned)time(NULL));
    s[start.x][start.y]++;
    while (!terminal(s, maxr, maxc)) {
        system("clear");
        printout(s, maxr, maxc);
        getchar();
        i = rand() % 8;
        x = start.x + xmove[i];
        y = start.y + ymove[i];
        if (x >= 0 && x < maxr && y >= 0 && y < maxc
            && s[x][y] <= MAXT) {
            s[x][y]++;
            totalmove++;
            start.x = x;
            start.y = y;
        }
    }
}

/* terminal: terminal contidion */
int terminal(int (*s)[COL], int maxr, int maxc)
{
    int i, j;

    for (i = 0; i < maxr; i++)
        for (j = 0; j < maxc; j++)
            if (s[i][j] == 0)
                return FALSE;

    return TRUE;
}

/* printout: print out result */
void printout(int (*s)[COL], int maxr, int maxc)
{
    int i, j;

    printf("\ntotal move: %d\n", totalmove);
    printf("count array:\n\n");
    for (i = 0; i < maxr; i++) {
        printf("%5d", s[i][0]);
        for (j = 1; j < maxc; j++)
            printf(" %5d", s[i][j]);
        putchar('\n');
    }
    putchar('\n');
}

ACM 371 Ackermann Functions

ACM100類似題。
兩個白爛點:
(1) 1的次數為3不為1 -.-。
(2) 未必是L H的input形式,有可能是H L。
但output還是要用L H的形式。 =.=

有夠白爛。
像這種定義有問題或是input/output不明確的題目都是爛題目。

/* ACM 371 Ackermann Functions
 * mythnc
 * 2011/11/30 08:23:02
 * run time: 0.128
 */
#include <stdio.h>

#define SWAP(X, Y, T) T = X, X = Y, Y = T

typedef struct max {
    int index, value;
} Max;

Max cal(int, int);
int count(long long);

int main(void)
{
    int i, j, tmp;
    Max m;

    while (scanf("%d %d", &i, &j) && i != 0) {
        if (i > j)
            SWAP(i, j, tmp);
        m = cal(i, j);
        printf("Between %d and %d, %d generates the longest sequence of %d values.\n",
               i, j, m.index, m.value);
    }

    return 0;
}

/* cal: find the big cycle len, and return it */
Max cal(int small, int big)
{
    int i, tmp;
    Max m;

    m.index = small;
    m.value = count(small);
    for (i = small + 1; i <= big && i > 0; i++) {
        tmp = count(i);
        if (m.value < tmp) {
            m.index = i;
            m.value = tmp;
        }
    }

    return m;
}

/* count: count the numbers of value n to 1 */
int count(long long n)
{
    int c;

    if (n == 1)
        return 3;

    for (c = 0; n != 1; c++)
        if (n % 2 == 0)
            n >>= 1;    /* n /= 2 */
        else 
            n = n * 3 + 1;

    return c;
}

20111129

ACM 439 Knight Moves

想好久的題目。
後來DS看完array了,
剛好exercise有一題也是knight move,
想說做完這題習題應該就能解這題ACM了,
結果悲劇,根本是不一樣的問題。
習題的題目:隨便給一個點,繞完西洋棋上每個點剛剛好一次。
這題:給兩點,由A點到B點的最短移動次數。

後來想到一種方法,不如從起始點A開始填數字(數字表示移動次數),
把西洋棋盤填滿,這樣就能知道A到B的移動次數。
但是有個問題,不知道能不能依序移動。
(後來看別人的作法,是可以依序移動)
依序移動的意思是,從某個點開始1, 2, 3一直往上填。
所以作法上保守一點,
就從A點開始,填滿所有的1,再從每個1中依序填滿所有的2,以此類推。
每填好一個,就丟到stack中,當所有的1都丟到stack中後,
最先丟進去的1要先拿出來用。依此類推。
有點first in first out的感覺。
應該叫quene不叫stack。

/* ACM 439 Knight Moves
 * mythnc
 * 2011/11/29 16:49:26   
 * run time: 0.024
 */
#include <stdio.h>
#include <string.h>

#define MAXCHAR 3  /* 2 + '\0' */
#define MAXS    8
#define RANGE(X) X >= 0 && X < MAXS

typedef struct point {
    int x; /* row */
    int y; /* col */
} Point;

Point stoc(char *);
void draw(int (*)[], Point);
void filln(int (*)[], Point, Point);

int count;
Point stack[MAXS * MAXS];

int main(void)
{
    char start[MAXCHAR], end[MAXCHAR];
    int square[MAXS][MAXS];
    Point from, to;

    while (scanf("%s %s", start, end) == 2) {
        /* init */
        memset(square, 0, sizeof(square));

        from = stoc(start);
        to = stoc(end);
        draw(square, from);

        printf("To get from %s to %s takes %d knight moves.\n",
                start, end, square[to.x][to.y]);
    }

    return 0;
}

/* stoc: string change to coordinate */
Point stoc(char *s)
{
    Point pt;
    pt.x = s[1] - '1';
    pt.y = s[0] - 'a';

    return pt;
}

/* draw: fill square with numbers */
void draw(int (*s)[MAXS], Point pt)
{
    int i, j;
    Point origin;

    origin.x = pt.x;
    origin.y = pt.y;
    count = 0;
    filln(s, pt, origin);

    for (i = 0; i < count; i++) {
        pt.x = stack[i].x;
        pt.y = stack[i].y;
        filln(s, pt, origin);
    }
}

/* filln: fill blocks to number n */
void filln(int (*s)[MAXS], Point pt, Point o)
{
    int i, x, y, n;
    int movex[] = {-2, -1, 1, 2, 2, 1, -1, -2};
    int movey[] = {1, 2, 2, 1, -1, -2, -2, -1};

    n = s[pt.x][pt.y] + 1;
    for (i = 0; i < 8; i++) {
        x = pt.x + movex[i];
        y = pt.y + movey[i];
        if (RANGE(x) && RANGE(y) && s[x][y] == 0
            && (x != o.x || y != o.y)) {
            s[x][y] = n;
            stack[count].x = x;
            stack[count].y = y;
            count++;
        }
    }
}

20111128

ACM 446 Kibbles `n' Bits `n' Bits `n' Bits

做進位轉換。

/* ACM 446 Kibbles `n' Bits `n' Bits `n' Bits
 * mythnc
 * 2011/11/28 10:07:08   
 * run time: 0.004
 */
#include <stdio.h>
#include <string.h>

#define MAXB  14
#define MAXH  4
#define OPR   2

int hextodec(char *);
int atod(char);
void dectobin(int, char *);
void reverse(char *);
int result(int, int, char *);

int main(void)
{
    char opd[2][MAXH];
    char opr[OPR];
    char b[2][MAXB];
    int d[2];
    int i;

    scanf("%*d");
    while (scanf("%s %s %s", opd[0], opr, opd[1]) == 3) {
        for (i = 0; i < 2; i++) {
            d[i] = hextodec(opd[i]);
            dectobin(d[i], b[i]);
            reverse(b[i]);
        }
        printf("%s %s %s = %d\n", b[0], opr, b[1], result(d[0], d[1], opr));
    }

    return 0;
}

/* hextodec: hex number change to decimal number */
int hextodec(char *s)
{
    int i, n, mul;

    mul = 1;
    for (n = 0, i = strlen(s) - 1; i > -1; i--) {
        n += mul * atod(s[i]);
        mul *= 16;
    }

    return n;
}

/* atoh: convert ascii code to decimal number */
int atod(char c)
{
    if (c >= '0' && c <= '9')
        return c - '0';

    return c - 'A' + 10;
}

/* dectobin: decimal number change to binary form */
void dectobin(int d, char *b)
{
    int i;

    for (i = 0; d != 0; i++) {
        b[i] = d % 2 + '0';
        d /= 2;
    }
    for (; i < MAXB - 1; i++)
        b[i] = '0';
    b[i] = '\0';
}

/* reverse: reverse b */
void reverse(char *b)
{
    int i, j;
    char tmp;

    for (i = 0, j = strlen(b) - 1; i < j; i++, j--) {
        tmp = b[i];
        b[i] = b[j];
        b[j] = tmp;
    }
}

/* result: depend on opr, do d1 + d2,
 * or d1 - d2 */
int result(int d1, int d2, char *opr)
{
    if (strcmp(opr, "+") == 0)
        return d1 + d2;

    return d1 - d2;
}

C語言做四捨五入

四捨五入如果知其道理,其實並沒有很難做。
把握一個原則:浮點數轉成整數,小數部位會全部捨去。
所以最簡單的作法就是,把浮點數加0.5,再轉成整數即可。
因為四以下要捨,五以上要入,所以加0.5。如果是負數,
則減去0.5。若是做四捨五入到小數第一位的話,就先乘10,
再加0.5,再除以10(唯要注意型態轉換),以此類推。

其實math.h中就有round()函式,但是是C99的東西。
或是用floor()跟ceil()實做也是ok的。

以下是程式碼。(寫個大概而已)

#include <stdio.h>

int round(double);

int main(void)
{
    double x;

    scanf("%lf", &x);
    printf("%d\n", round(x));

    return 0;
}

/* round: do round to x */
int round(double x)
{
    if (x > 0)
        return (int)(x + 0.5);

    return (int)(x - 0.5);
}




參考連結:
http://dejob.blogspot.com/2009/01/c-rounding.html
http://blog.xuite.net/freeleo168/Learn/19008875

ACM 10137 The Trip

討厭的浮點數運算,真是會整死人。
要做的事有兩個:
(1)四捨五入到cent
(2)找出最小的找零數

四捨五入下篇做詳解,反正就是那樣做。
找出最小的零頭,就是要作兩種版本的sum,
選擇其中之一較小的即可。

忘記寫return 0又吃了幾次RE = ="。

/* ACM 10137 The Trip
 * mythnc
 * 2011/11/27 20:38:34   
 * run time: 0.012
 */
#include <stdio.h>

#define MAXS 1000

double input(double *, int);
double roundoff(double);
double exchange(double *, double, int);

int main(void)
{
    double student[MAXS];
    double average;
    int n;

    while (scanf("%d", &n) && n != 0) {
        average = roundoff(input(student, n));
        printf("$%.2f\n", exchange(student, average, n));
    }

    return 0;
}

/* input: receive input data, return average cost */
double input(double *s, int n)
{
    int i;
    double sum;

    for (i = sum = 0; i < n; i++) {
        scanf("%lf", s + i);
        sum += s[i];
    }

    return sum / n;
}

/* roundoff: roundoff average to cent */
double roundoff(double money)
{
    return (int)(money * 100 + 0.5) / 100.0;
}

/* exchange: return total amount of exchange money */
double exchange(double *s, double average, int n)
{
    int i;
    double sum1, sum2;

    for (i = sum1 = sum2 = 0; i < n; i++) {
        if (s[i] > average)
            sum1 += s[i] - average;
        if (s[i] < average)
            sum2 += average - s[i];
    }

    return (sum1 < sum2) ? sum1 : sum2;
}

20111126

ACM 10161 Ant on a Chessboard

數值排列找規則。
若該數為x的平方數,那
一定是(1, x)或(x, 1),
看x是奇數或偶數。
若該數比平方數大,會有三種情況:
(1) 該數 - 平方數 == x + 1:
那就是在斜角(x + 1, x + 1)
(2) 該數 - 平方數 < x + 1:
(該數 - 平方數, n + 1)或(n + 1, 該數 - 平方數)
看x是奇數或偶數。
(3) 該數 - 平方數 > x + 1:
其中一個為n + 1,
另一個為n + 1 - [該數 - 平方數 - (n + 1)]
n + 1的意思是斜角。
算出與斜角的差值,再用此值與斜角相減。
(即從斜角的座標往前推)
化簡後為
2n + 2 - (該數 - 平方數)

/* ACM 10161 Ant on a Chessboard
 * mythnc
 * 2011/11/26 16:49:42   
 * run time: 0.004
 */
#include <stdio.h>
#include <math.h>

void output(int);

int main(void)
{
    int x;

    while (scanf("%d", &x) && x != 0)
        output(x);

    return 0;
}

/* output: output answer */
void output(int x)
{
    int n, value;

    if (x == 1) {
        printf("1 1\n");
        return;
    }

    n = sqrt(x);
    /* if x is a square number */
    if (n * n == x) {
        if (n % 2 == 1)
            printf("%d %d\n", 1, n);
        else
            printf("%d %d\n", n, 1);
        return;
    }
    /* if x bigger than a square number n */
    value = x - n * n;
    if (value == n + 1)
        printf("%d %d\n", n + 1, n + 1);
    else if (value < n + 1)
        if (n % 2 == 1)
            printf("%d %d\n", value, n + 1);
        else
            printf("%d %d\n", n + 1, value);
    else
        if (n % 2 == 1)
            printf("%d %d\n", n + 1, 2 * n - value + 2);
        else
            printf("%d %d\n", 2 * n - value + 2, n + 1);
}

20111125

ACM 414 Machined Surfaces

左邊跟右邊的XX合併,
合併後找出剩餘的space。

合併規則:左側最右與右側最左合併之。
那一定是左側 + 右側最多XX的那一個row,
會先併在一起。
也就是space最少的那個row。

所以找出space最小的row,
此row再跟其他row的space做相減加總後,
即為答案。

/* ACM 414 Machined Surfaces
 * mythnc
 * 2011/11/25 09:06:42   
 * run time: 0.004
 */
#include <stdio.h>

#define MAXCHAR 27 /* 25 + newline + '\0' */
#define MAXLINE 12

void input(char (*)[], int);
int count(char (*)[], int);

int main(void)
{
    char str[MAXLINE][MAXCHAR];
    int n, i;

    while (scanf("%d", &n) && n != 0) {
        getchar();   /* eat newline */
        input(str, n);
        printf("%d\n", count(str, n));
    }
    return 0;
}

/* input: receive input data */
void input(char (*s)[MAXCHAR], int n)
{
    int i;

    for (i = 0; i < n; i++)
        fgets(s[i], MAXCHAR, stdin);
}

/* count: return the count of remain space numbers */
int count(char (*s)[MAXCHAR], int n)
{
    int i, j, min, sum;
    int countb[MAXLINE];

    for (i = 0, min = 25; i < n; i++) {
        /* calculate space number in each row */
        for (j = countb[i] = 0; j < MAXCHAR; j++)
            if (s[i][j] == ' ')
                countb[i]++;
        /* find the minimum space number */
        if (min > countb[i])
            min = countb[i];
    }

    for (i = sum = 0; i < n; i++)
        sum += countb[i] - min;

    return sum;
}

20111124

ACM 412 Pi

排列組合 + 找出gcd為1的pair。
之後可求pi值。

/* ACM 412 Pi
 * mythnc
 * 2011/11/24 10:50:36   
 * run time: 0.124
 */
#include <stdio.h>
#include <math.h>

#define MAXN 49

void input(int *, int);
int comfactor(int *, int);
int gcd(int, int);

int main(void)
{
    int n, pair;
    int list[MAXN];

    while (scanf("%d", &n) == 1 && n != 0) {
        input(list, n);
        pair = comfactor(list, n);
        if (pair == 0) {
            printf("No estimate for this data set.\n");
            continue;
        }
        printf("%.6f\n", sqrt(3.0 / pair * n * (n - 1)));
    }
    return 0;
}

/* input: receive input data */
void input(int *list, int n)
{
    int i;

    for (i = 0; i < n; i++)
        scanf("%d", list + i);
}

/* comfactor: return no common factors pair numbers */
int comfactor(int *list, int n)
{
    int i, j, count;

    for (count = i = 0; i < n - 1; i++)
        for (j = i + 1; j < n; j++)
            if (gcd(list[i], list[j]) == 1)
                count++;

    return count;
}

/* gcd: calculate gcd of a and b */
int gcd(int a, int b)
{
    while ((a %= b) && (b %= a))
        ;

    return a + b;
}

20111123

ACM 10013 Super long sums

大數運算加法。
進位問題沒考慮好,WA一次。

9999 + 0001 = 0000。

/* ACM 10013 Super long sums
 * mythnc
 * 2011/11/23 14:17:30   
 * run time: 1.200
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXD 1000001

void bigsum(int *, int);
void print(int *, int);

int main(void)
{
    int set, i, m;
    int *sum;

    sum = (int *)malloc(sizeof(int) * MAXD);

    scanf("%d", &set);
    for (i = 0; i < set; i++) {
        /* init */
        memset(sum, 0, MAXD * sizeof(int));
        scanf("%d", &m);
        bigsum(sum, m);
        print(sum, m - 1);
        if (i < set - 1)
            putchar('\n');
    }

    free(sum);

    return 0;
}

/* bigsum: scan two number x, y, then do x + y */
void bigsum(int *sum, int m)
{
    int i, x, y;

    for (i = m - 1; i > - 1; i--) {
        scanf("%d %d", &x, &y);
        sum[i] += x + y;
    }
    /* carry */
    for (i = 0; i < m; i++)
        if (sum[i] > 9) {
            sum[i + 1] += sum[i] / 10;
            sum[i] %= 10;
        }
}

/* print: print out sum */
void print(int *sum, int m)
{
    for (; m > -1; m--)
        printf("%d", sum[m]);
    putchar('\n');
}

20111122

ACM 623 500!

一開始直接做超過3秒 TE。
只好事先算出答案,
結果忘記考慮0! ,
WA一次。

/* ACM 623 500!
 * mythnc
 * 2011/11/22 21:08:08   
 * run time: 0.084
 */
#include <stdio.h>

#define MAXD 2600
#define MAXN 1001

int mul(int *, int);
void copy(int *, char *, int);

int main(void)
{
    int n, i, digit;
    int big[MAXD] = { 1 };
    char fac[MAXN][MAXD];
    /* precalculate */
    for (i = 0; i < MAXN; i++) {
        digit = mul(big, i);
        copy(big, fac[i], digit);
    }

    while (scanf("%d", &n) == 1)
        printf("%d!\n%s", n, fac[n]);

    return 0;
}

/* mul: do b * n return its digit */
int mul(int *b, int n)
{
    int i;

    if (n == 0)
        return 0;

    for (i = 0; i < MAXD; i++)
        b[i] *= n;
    /* carry */
    for (i = 0; i < MAXD - 1; i++)
        if (b[i] > 9) {
            b[i + 1] += b[i] / 10;
            b[i] %= 10;
        }
    /* find digit */
    for (i = MAXD - 1; b[i] == 0 && i > -1; i--)
        ;

    return i;
}

/* copy: copy b to f */
void copy(int *b, char *f, int d)
{
    int i;

    for (i = 0; d > -1; i++, d--)
        f[i] = b[d] + '0';
    f[i++] = '\n';
    f[i] = '\0';
}

20111121

ACM 10921 Find the Telephone

map then output。

做了快100題了,
之前都是一天兩題。
之後每天做一題就好。
現在的題目難易落差明顯。
增強實力吧~!

/* ACM 10921 Find the Telephone
 * mythnc
 * 2011/11/21 12:12:59   
 * run time: 0.004
 */
#include <stdio.h>

#define MAXCHAR 31

void trans(char *);

int main(void)
{
    char s[MAXCHAR];

    while (scanf("%s", s) == 1) {
        trans(s);
        printf("%s\n", s);
    }
    return 0;
}

/* trans: translate s into the form of telephone number */
void trans(char *s)
{
    int i;
    char map[] = {'2', '2', '2', '3', '3', '3', '4', '4', '4', '5',
                  '5', '5', '6', '6', '6', '7', '7', '7', '7', '8',
                  '8', '8', '9', '9', '9', '9'};

    for (i = 0; s[i] != '\0'; i++)
        if (s[i] >= 'A' && s[i] <= 'Z')
            s[i] = map[s[i] - 'A'];
}

20111120

ACM 484 The Department of Redundancy Department

Linked list。
好久沒寫都快忘光惹 @_@。

/* ACM 484 The Department of Redundancy Department
 * mythnc
 * 2011/11/20 14:10:46   
 * run time: 0.480
 */
#include <stdio.h>
#include <stdlib.h>

typedef struct number {
    int name;
    int count;
    struct number *next;
} Number;

Number *addnumber(int, Number *);
void print(Number *);
void freenumber(Number *);

int main(void)
{
    Number *root;
    int n;

    root = NULL;
    while (scanf("%d", &n) == 1)
        root = addnumber(n, root);

    print(root);
    freenumber(root);

    return 0;
}

/* addnumber: add number in p */
Number *addnumber(int n, Number *p)
{
    if (p == NULL) {
        p = (Number *)malloc(sizeof(Number));
        p->name = n;
        p->count = 1;
        p->next = NULL;
    }
    else if (p->name == n)
        p->count++;
    else
        p->next = addnumber(n, p->next);

    return p;
}

/* print: print p */
void print(Number *p)
{
    while (p != NULL) {
        printf("%d %d\n", p->name, p->count);
        p = p->next;
    }
}

/* freenumber: free p */
void freenumber(Number *p)
{
    Number *tmp;

    while (p != NULL) {
        tmp = p;
        free(tmp);
        p = p->next;
    }
}

20111119

ACM 10929 You can say 11

判斷是否為11的倍數。

做(奇數位數和 - 偶數位數和) % 11即可。

神秘的數字11。

/* ACM 10929 You can say 11
 * mythnc
 * 2011/11/19 22:51:54   
 * run time: 0.016
 */
#include <stdio.h>

#define MAXCHAR 1001

int mul11(char *);

int main(void)
{
    char s[MAXCHAR];

    while (scanf("%s", s) == 1 && (s[0] != '0' || s[1] != '\0'))
        if (mul11(s))
            printf("%s is a multiple of 11.\n", s);
        else
            printf("%s is not a multiple of 11.\n", s);

    return 0;
}

/* mul11: return 1 if s can be expressed 11n
 * else return 0 */
int mul11(char *s)
{
    int i, odd, even;

    for (i = odd = even = 0; s[i] != '\0'; i++)
        if (i % 2 == 0)
            odd += s[i] - '0';
        else
            even += s[i] - '0';

    return (odd - even)% 11 == 0;
}

ACM 10260 Soundex

字轉成數字,
重複跟0不做輸出。

/* ACM 10260 Soundex
 * mythnc
 * 2011/11/19 21:42:21   
 * run time: 0.004
 */
#include <stdio.h>

#define MAXCHAR 20

void print(char *);

int main(void)
{
    char str[MAXCHAR];
    
    while (scanf("%s", str) == 1)
        print(str);
    return 0;
}

/* print: print out sounedex code */
void print(char *s)
{
    int map[26] = {0, 1, 2, 3, 0,
                   1, 2, 0, 0, 2,
                   2, 4, 5, 5, 0,
                   1, 2, 6, 2, 3,
                   0, 1, 0, 2, 0, 2};

    int stack, i;

    for (stack = -1, i = 0; s[i] != '\0'; i++)
        if (stack != map[s[i] - 'A'])
            if (map[s[i] - 'A'] != 0) {
                printf("%d", map[s[i] - 'A']);
                stack = map[s[i] - 'A'];
            }
            else
                stack = -1;
    putchar('\n');
}

20111118

ACM 10924 Prime Words

判斷質數。
ACM有些題目會把1定義為質數,
但1明明就不是質數,
真瞎,快改吧!

/* ACM 10924 Prime Words
 * mythnc
 * 2011/11/18 09:56:41   
 * run time: 0.004
 */
#include <stdio.h>
#include <string.h>
#include <math.h>

#define MAXCHAR 21
#define TRUE    1
#define FALSE   0

int sumw(char *);
int prime(int n);

int main(void)
{
    char str[MAXCHAR];

    while (scanf("%s", str) == 1) {
        if (prime(sumw(str)))
            printf("It is a prime word.\n");
        else
            printf("It is not a prime word.\n");
    }
    return 0;
}

/* sumw: sum of the word letters */
int sumw(char *s)
{
    int i, sum;

    for (i = sum = 0; i < strlen(s); i++)
        if (s[i] >= 'a' && s[i] <= 'z')
            sum += s[i] - 'a' + 1;
        else if (s[i] >= 'A' && s[i] <= 'Z')
            sum += s[i] - 'A' + 27;

    return sum;
}

/* prime: return TRUE if n is prime,
 * else return FALSE */
int prime(int n)
{
    int i;

    if (n == 2)
        return TRUE;

    if (n % 2 == 0)
        return FALSE;

    for (i = 3; i <= sqrt(n); i += 2)
        if (n % i == 0)
            return FALSE;

    return TRUE;
}

ACM 324 Factorial Frequencies

大數運算乘法。
再找0~9出現次數。

/* ACM 324 Factorial Frequencies
 * mythnc
 * 2011/11/18 09:13:32   
 * run time: 0.012
 */
#include <stdio.h>

#define MAXD 781

void init(int *, int);
int mul(int *, int);
void countdec(int *, int, int *);
void print(int, int *);

int main(void)
{
    int n, count;
    int seq[MAXD];
    int dec[10];

    while (scanf("%d", &n) && n != 0) {
        init(seq, MAXD);
        init(dec, 10);
        count = mul(seq, n);
        countdec(seq, count, dec);
        print(n, dec);
    }
    return 0;
}

/* init: initialized s to zero */
void init(int *s, int n)
{
    int i;

    for (i = 0; i < n; i++)
        s[i] = 0;
}

/* mul: calculate n!,
 * return its digit number */
int mul(int *s, int n)
{
    int i, j;

    for (s[0] = 1, i = 2; i < n + 1; i++) {
        for (j = 0; j < MAXD; j++)
            s[j] *= i;
            /* carry */
        for (j = 0; j < MAXD; j++)
            if (s[j] > 9) {
                s[j + 1] += s[j] / 10;
                s[j] %= 10;
            }
    }

    for (i = MAXD - 1; s[i] == 0; i--)
        ;

    return i + 1;
}

/* countdec: count 0~9 times */
void countdec(int *s, int n, int *d)
{
    int i;

    for (i = 0; i < n; i++)
        d[s[i]]++;
}

/* print: print out result */
void print(int n, int *d)
{
    int i;

    printf("%d! --\n", n);
    for (i = 0; i < 10; i++) {
        if (i == 5)
            printf("\n");
        if (i != 0 && i != 5)
            printf(" ");
        printf("   (%d)%5d", i, d[i]);
    }
    printf("\n");
}

ACM 583 Prime Factors

質因數分解。
沒用sqrt就TL,
用sqrt變超快!
看來我的i * i <= n以後都要寫,
i <= sqrt(n)了 。

/* ACM 583 Prime Factors
 * mythnc
 * 2011/11/17 22:56:12   
 * run time: 0.340
 */
#include <stdio.h>
#include <math.h>

void factor(int);
int print(int, int);

int main(void)
{
    int n;

    while (scanf("%d", &n) && n != 0) {
        printf("%d = ", n);
        if (n < 0) {
            printf("-1 x ");
            n *= -1;
        }
        factor(n);
    }
    return 0;
}

/* factor: find prime factor and print it */
void factor(int n)
{
    int i;
    /* even */
    while (n % 2 == 0 && n != 1)
        n = print(n, 2);
    if (n == 1)
        return;
    /* odd */
    for (i = 3; i <= sqrt(n) && n != 1; i += 2)
        while (n % i == 0 && n != 1)
            n = print(n, i);
    if (n == 1)
        return;
    /* prime */
    if (n != 1)
        printf("%d\n", n);
}

/* print: print prime and return n */
int print(int n, int i)
{
    n /= i;
    if (n == 1) {
        printf("%d\n", i);
        return 1;
    }
    else
        printf("%d x ", i);

    return n;
}

20111117

ACM 350 Pseudo-Random Numbers

search。
注意不一定從種子開始,
也就意味第一個數可能是非cycle數。

/* ACM 350 Pseudo-Random Numbers
 * mythnc
 * 2011/11/17 21:48:38   
 * run time: 1.1
 */
#include <stdio.h>

#define MAXR  10000

int len(int, int, int, int);
int in(int, int *, int);

int main(void)
{
    int z, inc, mod, last, set;

    set = 0;
    while (scanf("%d %d %d %d", &z, &inc, &mod, &last) && mod != 0)
        printf("Case %d: %d\n", ++set, len(z % mod, inc % mod, mod, last));

    return 0;
}

/* len: return the len */
int len(int z, int inc, int mod, int last)
{
    int i, tmp, seed;
    int r[MAXR];

    r[0] = last;
    for (i = 1; ; i++) {
        tmp = (r[i - 1] * z + inc) % mod;
        if ((seed = in(tmp, r, i)) != -1)
            return i - seed;
        r[i] = tmp;
    }
}

/* in: if n in r,
 * i = 0 mean start from seed return TRUE,
 * i > 0 mean start not from seed return i,
 * else return -1 */
int in(int n, int *r, int count)
{
    int i;

    for (i = 0; i < count; i++)
        if (r[i] == n)
            return i;

    return -1;
}

ACM 294 Divisors

找因數。
ACM 160類似。

先做質因數分解,再用質因數分解的答案算出所有因數。
例如6是 2^1 * 3^1,所以6的所有因數為(1 + 1) * (1 + 1) = 4。
題目已經告訴我們1000000000中最多是192個因數。
所以會用到的質數一定小於192。
但這時候會有個問題,如果是給的值,是第193以後的質數怎麼辦?
因為質數只能被自己跟1整除,所以也不會被其他質數整除。
反正質數的因數就只有2個,所以質數也可以處理了。

老實說我一開始沒想到第193個質數之後的情況,
但寫出來的程式碼也誤打誤撞AC =.=,
可能測資過了,但程式碼還是要修。
後來終於找到一個想法跟我差不多的人寫得程式碼,
好厲害!他補完了我沒想到的部份:
連結

完整假設是這樣:
因為合數必定可以拆成兩個質數相乘。
如果存在一組質數,使得p1 * p2 > 1000000000,
而p1, p2之前的質數相乘都能 < 1000000000的話,
那麼在1000000000這些數中,
最多最多會用到的質數,就是比p1或p2小的質數,
這要怎麼證明呢?
因為合數n必定可以拆成a * b,
a跟b必有一數大於等於根號n,另一數小於等於根號n,
所以我們只要找等於根號n的那個質數即可。
大於等於根號n的質數不用找,因為a跟b都要考慮,
若一個是大於等於根號n,那另一個必定小於等於根號n,
如此,只要找到小於等於根號n的所有情況,
也就滿足所有情況了。
第3401個質數為31607,31607的平方為999002449,
第3402個質數為31627,31627的平方為1000267129。
所以最多最多會用到的質數就是第3401個質數為31607。

總結,
只要考慮能被前3402個質數整除即可,
再用質因數分解的方式去找所有質數即可。
若合數n最後不是等於1,表示存在一個質數p,
使得前3402個質數都無法整除此質數p。
這種情況也不用擔心,因為能整除質數數只有兩種,
1跟他自己。
所以再把答案 * 2即可。

/* ACM 294 Divisors
 * mythnc
 * 2011/11/17 12:13:07   
 * run time: 0.032
 */
#include <stdio.h>

#define MAXP  3402
#define TRUE  1
#define FALSE 0

typedef struct divisor {
    int number, count;
} Divisor;

typedef struct big {
    int number, sum;
} Big;

void findp(Divisor *);
Big maxn(Divisor *, int, int);
int dnumber(Divisor *, int);

int main(void)
{
    int head, tail;
    Big max;
    Divisor prime[MAXP];

    findp(prime);
    scanf("%*d");
    while (scanf("%d %d", &head, &tail) == 2) {
        max = maxn(prime, head, tail);
        printf("Between %d and %d, %d has a maximum of %d divisors.\n"
                , head, tail, max.number, max.sum);
    }
    return 0;
}

/* findp: find n primes */
void findp(Divisor *p)
{
    int count, i, j, flag;

    p[0].number = 2;
    count = 1;
    for (i = 3; count < MAXP; i += 2) {
        for (flag = TRUE, j = 3; j * j <= i; j++)
            if (i % j == 0) {
                flag = FALSE;
                break;
            }
        if (flag)
            p[count++].number = i;
    }
}

/* maxn: return the number which has the max divisors */
Big maxn(Divisor *p, int head, int tail)
{
    int i, number;
    Big max;

    max.number = head;
    max.sum = dnumber(p, head);
    for (i = head + 1; i < tail + 1; i++) {
        number = dnumber(p, i);
        if (max.sum < number) {
            max.sum = number;
            max.number = i;
        }
    }

    return max;
}

/* dnumber: return number of divisors of n */
int dnumber(Divisor *p, int n)
{
    int i, j, d;

    if (n == 1)
        return 1;

    for (i = 0; i < MAXP && n != 1; i++) {
        p[i].count = 0;
        while (n % p[i].number == 0) {
            n /= p[i].number;
            p[i].count++;
        }
    }

    for (d = 1, j = 0; j < i; j++)
        if (p[j].count != 0)
            d *= p[j].count + 1;

    if (n != 1)
        return d * 2;
    return d;
}

20111116

USACO Barn Repair

被婊到……
USACO的Greedy Algorithm說明文寫得根本不是Greedy Algorithm……
什麼求n = 5時先求n = 4的最佳解,害我想到DP去。
(因為n = 4的最佳解必定是n = 3的最佳解……根本就是從n = 1往上推的意思)

如果演算法正確還ok,
問題是DP的code到測資第5組就gg惹 =.=。
你說這不會讓人想殺人嗎?

其實也不用管什麼Greedy不Greedy的,
直接想作法還比較實際……
Greedy Algorithm這名詞真是抽象無比。

先對C做sort。
接著算出每個C之間的間距,一樣sort。
再計算只用1塊板子的長度Len,
當m = 1表示用1塊板子,Len就是答案。
m = 2時,Len要減去最大間距,
m = 3時,Len要減去最大間距與次大間距。
若m >= C,直接output C。
其實就這樣而已……

另外fopen本來就要fclose吧?
USACO的code從不做fclose,
無言。

盡信書不如無書。
一堆google別人想的解法還比USACO的好太多了 = =。
/*
ID: mythnc2
LANG: C
TASK: barn1
barn repair
2011/11/16 16:21:20   
*/
#include <stdio.h>
#include <stdlib.h>

#define MAXARY 200

int cmp(const void *, const void *);

int main (void)
{
    FILE *fin, *fout;
    int n, nc, i, sum;
    int ary[MAXARY], diff[MAXARY];

    fin = fopen("barn1.in", "r");
    fout = fopen("barn1.out", "w");

    fscanf(fin, "%d %*d %d", &n, &nc);
    for (i = 0; i < nc; i++)
        fscanf(fin, "%d", ary + i);

    if (n < nc) {
        qsort(ary, nc, sizeof(int), cmp);
        for (i = 0; i < nc - 1; i++)
            diff[i] = ary[i + 1] - ary[i] - 1;
        qsort(diff, nc - 1, sizeof(int), cmp);
        sum = ary[nc - 1] - ary[0] + 1;
        for (i = nc - 2; n > 1 ; i--, n--)
            sum -= diff[i];
        fprintf(fout, "%d\n", sum);
    }
    else
        fprintf(fout, "%d\n", nc);

    fclose(fin);
    fclose(fout);
    return 0;
}

/* cmp: function of qsort argument */
int cmp(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}

ACM 492 Pig-Latin

一個字元一個字元慢慢吃,
再判斷是否是字母。
是就存起來,
當遇到非字母時,就output改過的單字。

有一點stack的味道。

/* ACM 492 Pig-Latin
 * mythnc
 * 2011/11/16 11:50:51   
 * run time: 0.028
 */
#include <stdio.h>
#include <ctype.h>

#define MAXCHAR 1000

void print(char *);

int main(void)
{
    char word[MAXCHAR];
    int c, i;

    i = 0;
    while ((c = getchar()) != EOF)
        if (isalpha(c))
            word[i++] = c;
        else {
            if (i != 0) {
                word[i] = '\0';
                print(word);
                i = 0;
            }
            putchar(c);
        }
    return 0;
}

/* print: print out word in pig-latin form */
void print(char *w)
{
    switch (w[0]) {
        case 'A':
        case 'a':
        case 'E':
        case 'e':
        case 'I':
        case 'i':
        case 'O':
        case 'o':
        case 'U':
        case 'u':
            printf("%say", w);
            break;
        default:
            printf("%s%cay", w + 1, w[0]);
    }
}

ACM 568 Just the Facts

乘法進位問題。
每次補0就要移到下一位,
下一位的數字又是取決於乘法進位。
所以直接只用最後幾個位數做乘法是不行的,
因為只要有0就要考慮下一個數。
15!就已經有2個0了。

所以採取的作法是半大數,只計算最後100位數,
至於為什麼是100位數呢?
我只是取一個不會被乘法進位問題干涉到的值,
或許50位數應該也ok吧?可以試試,
或是有其他比較好的作法。

/* ACM 568 Just the Facts
 * mythnc
 * 2011/11/16 10:06:34   
 * run time: 0.016
 */
#include <stdio.h>

#define MAXN 10001
#define MAXD 100

void init(int *, char *);

int main(void)
{
    int n;
    int digit[MAXD] = { 0 };
    char save[MAXN];

    init(digit, save);
    while (scanf("%d", &n) == 1)
        printf("%5d -> %c\n", n, save[n]);

    return 0;
}

/* init: precalculate answer,
 * save last non-zero in array save */
void init(int *d, char *s)
{
    int i, j, k;

    s[0] = '0';
    d[0] = 1;
    for (i = 1; i < MAXN; i++) {
        for (j = 0; j < MAXD; j++)
            d[j] *= i;
        /* carry */
        for (j = 0; j < MAXD - 1; j++)
            if (d[j] > 9) {
                d[j + 1] += d[j] / 10;
                d[j] %= 10;
            }
        /* remove zero */
        if (i > 4) {
            for (j = 0; d[j] == 0; j++)
                ;
            for (k = 0; j < MAXD; j++, k++)
                d[k] = d[j];
            for (; k < MAXD; k++)
                d[k] = 0;
        }
        /* copy last digit to s */
        s[i] = d[0] + '0';
    }
}

20111115

ACM 572 Oil Deposits

ACM10189類似。

(1) 找到@之後,把@轉變為*,
(2) 並再找其四面八方的是否存在@,
反覆(1)跟(2)。

一次傳超過4個變數有點討厭,
所以就用全域了……。

/* ACM 572 Oil Deposits
 * mythnc
 * 2011/11/29 15:17:44   
 * version 2  
 * run time: 0.004
 */
#include <stdio.h>

#define MAXROW 100
#define MAXCOL 101
#define TRUE   1
#define FALSE  0

int row, col;

int sweep(char (*g)[MAXCOL]);
void clear(char (*g)[MAXCOL], int i, int j);

int main(void)
{
    char grid[MAXROW][MAXCOL];
    int i;

    while (scanf("%d %d", &row, &col) && row != 0) {
        for (i = 0; i < row; i++)
            scanf("%s", grid[i]);

        printf("%d\n", sweep(grid));
    }
    return 0;
}

/* sweep: sweep and return distinct oil number */
int sweep(char (*g)[MAXCOL])
{
    int count, i, j;

    for (count = i = 0; i < row; i++)
        for (j = 0; j < col; j++)
            if (g[i][j] == '@') {
                count++;
                clear(g, i, j);
            }

    return count;
}

/* clear: clear '@' to '*' */
void clear(char (*g)[MAXCOL], int i, int j)
{
    int mover[] = {1, 1, 1, 0, -1, -1, -1, 0};
    int movec[] = {-1, 0, 1, 1, 1, 0, -1, -1};
    int k, x, y;

    g[i][j] = '*';
    for (k = 0; k < 8; k++) {
        x = i + mover[k];
        y = j + movec[k];
        if (x >= 0 && x < row && y >= 0 && y < col
            && g[x][y] == '@')
            clear(g, x, y);
    }
}

ACM 438 The Circumference of the Circle

給三點,求其外接圓周長。

已知3點ABC,相對應的外接圓直徑為,
abc / 2 * area。
area由海龍公式可得,
根號[s * (s - a) * (s - b) * (s - c)],
s為周長 / 2。
代入化簡可得圓周長為:
pi * 2abc / 根號的[(a + b + c) * (b + c - a) * (a + b - c ) * (a + c - b)]

/* ACM 438 The Circumference of the Circle
 * mythnc
 * 2011/11/15 12:26:59   
 * run time: 0.012
 */
#include <stdio.h>
#include <math.h>

#define MAXP 3

typedef struct coordinates {
    double x;
    double y;
} Coordinates;

double diameter(Coordinates *);
double distance(Coordinates, Coordinates);

int main(void)
{
    Coordinates point[MAXP];
    int i;
    double const pi = 3.141592653589793;

    while (scanf("%lf %lf", &point[0].x, &point[0].y) == 2) {
        for (i = 1; i < MAXP; i++)
            scanf("%lf %lf", &point[i].x, &point[i].y);
        printf("%.2lf\n", pi * diameter(point));
    }
    return 0;
}

/* circum: return the diameter value */
double diameter(Coordinates *point)
{
    double a, b, c;

    a = distance(point[0], point[1]);
    b = distance(point[1], point[2]);
    c = distance(point[2], point[0]);

    return 2 * a * b * c
           / sqrt((a + b + c) * (b + c - a) * (a + c - b) * (a + b - c));
}

/* distance: return the distance between p1 and p2 */
double distance(Coordinates p1, Coordinates p2)
{
    return sqrt(pow(p1.x - p2.x, 2) + pow(p1.y - p2.y, 2));
}

20111114

USACO Mixing Milk

原來這種算則就叫greedy algorithm……

每次找最便宜的milk,
接著確認amount供應是否正常,
反覆此二步驟,直到滿足amount量,
輸出金額。

先做sort好像會比較好一點……

/*
ID: mythnc2
LANG: C
TASK: milk
Mixing Milk
2011/11/14 21:57:02
*/
#include <stdio.h>

#define MAXF 5000

typedef struct provider {
    int price;
    int amount;
} Provider;

int findmin(Provider *, int);
int checkamount(Provider, int);

int main (void)
{
    FILE *fin, *fout;
    int amount, farmer, i, sum, min, quan;
    Provider milk[MAXF];

    fin = fopen("milk.in", "r");
    fout = fopen("milk.out", "w");

    fscanf(fin, "%d %d", &amount, &farmer);
    for (i = 0; i < farmer; i++)
        fscanf(fin, "%d %d", &milk[i].price, &milk[i].amount);

    for (sum = 0; amount; milk[min].price = 1001) {
        min = findmin(milk, farmer);
        quan = checkamount(milk[min], amount);
        sum += quan * milk[min].price;
        amount -= quan;
    }

    fprintf(fout, "%d\n", sum);

    return 0;
}

/* findmin: return the minimum milk.price element */
int findmin(Provider *milk, int n)
{
    int i, min;

    for (i = 1, min = 0; i < n; i++)
        if (milk[i].price < milk[min].price)
            min = i;

    return min;
}

/* checkamount: return the milk.amount provide
 * actually */
int checkamount(Provider milk, int amount)
{
    if (milk.amount > amount)
        return amount;

    return milk.amount;
}

USACO Dual Palindromes

Palindromic Squares類似。
要注意S雖然有範圍,
但主要是求出N的個數,
個數有可能超過S的範圍。

/*
ID: mythnc2
LANG: C
TASK: dualpal
Dual Palindromes
2011/11/14 20:30:40   
*/
#include <stdio.h>
#include <string.h>

#define MAXCHAR 15
#define TRUE    1
#define FALSE   0

void conversion(int, int, char *);
int pal(char *);

int main (void)
{
    FILE *fin, *fout;
    int n, s, i, j, count;
    char t[MAXCHAR];

    fin = fopen("dualpal.in", "r");
    fout = fopen("dualpal.out", "w");

    fscanf(fin, "%d %d", &n, &s);

    for (i = s + 1; n; i++)
        for (count = 0, j = 2; j < 11; j++) {
            conversion(j, i, t);
            if (pal(t))
                count++;
            if (count > 1) {
                fprintf(fout, "%d\n", i);
                n--;
                break;
            }
        }

    return 0;
}

/* conversion: conver n in base of b,
 * save in t */
void conversion(int b, int n, char *t)
{
    int i, mod;
    char map[] = "0123456789";

    for (i = 0; n; i++) {
        t[i] = map[n % b];
        n /= b;
    }
    t[i] = '\0';
}

/* pal: if t is palindrome return TRUE,
 * else return FALSE */
int pal(char *t)
{
    int i, j;

    for (i = 0, j = strlen(t) - 1; i < j; i++, j--)
        if (t[i] != t[j])
            return FALSE;

    return TRUE;
}

ACM 490 Rotating Sentences

順時針轉90度角。
每行的\n不要處理。
範例測資很怪,h後面有space,但r跟e後面就沒有……
我寫的AC code有補space。

/* ACM 490 Rotating Sentences
 * mythnc
 * 2011/11/14 19:22:42   
 * run time: 0.008
 */
#include <stdio.h>
#include <string.h>

#define MAXLINE 100
#define MAXCHAR 105

int maxlen(char (*seq)[MAXCHAR], int n);

int main(void)
{
    char seq[MAXLINE][MAXCHAR];
    int count, i, j;

    count = 0;
    while (fgets(seq[count], MAXCHAR, stdin))
        count++;

    for (i = 0; i < maxlen(seq, count); i++, putchar('\n'))
        for (j = count - 1; j > -1; j--)
            if (i >= strlen(seq[j]) - 1)
                putchar(' ');
            else
                printf("%c", seq[j][i]);

    return 0;
}

/* maxlen: return max string length */
int maxlen(char (*seq)[MAXCHAR], int n)
{
    int i, max;

    for (i = max = 0; i < n; i++)
        if (max < strlen(seq[i]))
            max = strlen(seq[i]);

    return max - 1;  /* we don't need '\n' */
}

ACM 10006 Carmichael Numbers

一開始以為只要算prime就好了,真是好天真,
馬上得到WA一枚。

Carmichael number的意思:
某數經由Fermat Test算出為質數,
但實際上為合數的數,就稱為Carmichael number。

也就是判斷n是否由Fermat Test算出來是質數,
但實際上是合數即可。

Fermat Test是關鍵,因為要算mod,
雖然跟ACM374,但我那題的解法在這題卻不適用。
一個比較好的算則是mod的分配律:
假設 (a * b) % m,可以拆為:
(a % m) * (b % m)。
同理,a^2 % m可以拆為,
(a % m) * (a % m)。
如此就可以把a^n一路往下拆,拆到n為1或0為止。
然而最大數為64998 ^ 2為4224740004,
所以要用unsigned。

有兩種作法,先算出1到65000的Carmichael number,
若測資為這些數,可直接做輸出。

第二種方法,直接做,但演算法要正確且快速,否則會TL。
判斷數字n是否是質數,是質數的情況下,必不為Carmichael number,
若n滿足Fermat Test,要再判斷n是否為質數。
C語言的&&運算子為short-circuit evaluation,
所以質數判斷放前面,Fermat Test判斷放後面,
會比較快。

/* ACM 10006 Carmichael Numbers
 * mythnc
 * 2011/11/14 16:53:51   
 * run time: 0.144
 */
#include <stdio.h>

#define FALSE 0
#define TRUE  1

int prime(int);
int fermat(int);
unsigned int powermod(int a, int n, int d);

int main(void)
{
    int n;

    while (scanf("%d", &n) && n != 0)
        if (!prime(n) && fermat(n))
            printf("The number %d is a Carmichael number.\n", n);
        else
            printf("%d is normal.\n", n);

    return 0;
}

/* fermat: do Fermat test,
 * if n is prime return TRUE,
 * else return FALSE.
 * WARNING: it means in Fermat test is a prime,
 * maybe it isn't really a prime */
int fermat(int n)
{
    int i;

    for (i = 2; i < n; i++)
        if (powermod(i, n, n) != i)
            return FALSE;

    return TRUE;
}

/* powermod: calculate mod value,
 * in recursive method,
 * return big mod number */
unsigned int powermod(int a, int n, int d)
{
    unsigned int x;

    if (n == 0)
        return 1;
    if (n == 1)
        return a % d;
    
    x = powermod(a, n / 2, d);
    x = x * x % d;
    if (n % 2 == 0)
        return x;
    else
        return x * a % d;
}

/* prime: return TRUE if n is prime,
 * else return FALSE */
int prime(int n)
{
    int i;

    for (i = 3; i * i <= n; i++)
        if (n % i == 0)
            return FALSE;

    return TRUE;
}

ACM相關網站

有很多人都在寫ACM,有時候想不到好的演算法時,看看別人怎麼想,別人怎麼解題,也是一種學習。

國內
翼世界夢想領域
http://maplewing.blogspot.com/

Ya-Lin Huang's ACM Problemset
http://yalin.tw/acm.php

調和的靈感
http://chchwy.blogspot.com/p/my-solved-acm-problems-list.html

Robert Anderson's Blog
http://www.wretch.cc/blog/robertanders

摸索C語言
http://mypaper.pchome.com.tw/zerojudge
http://mypaper.pchome.com.tw/iustlovefish

ACM解題筆記
http://kos74185foracm.blogspot.com/

The Tagtraum House
http://tagtraumhouse.blogspot.com/

國外
algorithmist
http://www.algorithmist.com/index.php/Category:UVa_Online_Judge

World of Seven
http://www.comp.nus.edu.sg/~stevenha/programming/acmoj.html

ACM 138 Street Numbers

直接做會算到天荒地老,第7組電腦跑了一個小時還跑不出來,
暴力是不行滴!

google或是看uva討論板,都是寫些我看不懂的算則(遮臉),
最後在這裡
終於看到一個看得懂的算則了。
很直觀的想法,但我竟然沒想到 orz。

大意就是門牌號碼i往上遞增時,左邊的總數加第i - 1個號碼,
右邊的總數先減去第i個號碼,再從j + 1開始往上加,直到找到滿10組解。
(ps 要先找到第一組解才行)

/* ACM 138 Street Numbers
 * mythnc
 * 2011/11/14 07:54:27   
 * run time: 0.3
 */
#include <>

int main(void)
{
    long long i, j, pre, next;
    int count;

    printf("%10d%10d\n", 6, 8);
    pre = next = 15;
    j = 9;
    for (i = 7, count = 1; count < 10; i++) {
            pre += i - 1;
            next -= i;
        for (; next < pre; j++)
            next += j;
        if (next == pre) {
            printf("%10lld%10lld\n", i, j - 1);
            count++;
        }
    }
    return 0;
}

ACM 10302 Summation of Polynomials

算立方和。
其實我看不懂他題目在推導蝦米,
{n}他寫得真怪……

/* ACM 10302 Summation of Polynomials
 * mythnc
 * 2011/11/14 07:28:09   
 * run time: 0.016
 */
#include <stdio.h>

int main(void)
{
    long long n;

    while (scanf("%lld", &n) == 1)
        printf("%lld\n", n * n * (n + 1) * (n + 1) / 4);

    return 0;
}

20111113

ACM 10222 Decode the Mad man

ACM10082
做mapping。

/* ACM 10222 Decode the Mad man
 * mythnc
 * 2011/11/13 14:52:11   
 * run time: 0.004
 */
#include <stdio.h>
#include <string.h>

int main(void)
{
    char key[] = "`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./";
    int map[256];
    int i, c;
    /* mapping */
    for (i = 0; i < strlen(key); i++)
        map[key[i]] = key[i - 2];

    while ((c = getchar()) != EOF) {
        if (c == ' ' || c == '\n') {
            putchar(c);
            continue;
        }
        if (c >= 'A' && c <= 'Z')  /* upper case */
            c = c - 'A' + 'a';
        putchar(map[c]);
    }
    return 0;
}

ACM 10106 Product

大數運算,乘法。

每次都死在邊界問題啊……
0 * 0 = 0

/* ACM 10106 Product */
/* mythnc
 * 2011/11/13 13:12:16   
 * run time: 0.008
 */
#include <stdio.h>
#include <string.h>

#define MAXCHAR 251
#define MAXD    500

void init(int *);
void reverse(char *);
void mul(char *, char *, int *);
int ctoi(char);
void print(int *);

int main(void)
{
    char x[MAXCHAR], y[MAXCHAR];
    int product[MAXD];

    while (scanf("%s\n%s", x, y) == 2) {
        init(product);
        reverse(x);
        reverse(y);
        mul(x, y, product);
        print(product);
    }
    return 0;
}

/* init: initialize product */
void init(int *p)
{
    memset(p, 0, MAXD * sizeof(int));
}

/* reverse: reverse char arrry s */
void reverse(char *s)
{
    int i, j;
    char tmp;

    for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}

/* mul: do x * y save result in p */
void mul(char *x, char *y, int *p)
{
    int i, j, lenx, leny;

    lenx = strlen(x);
    leny = strlen(y);
    for (i = 0; i < lenx; i++)
        for (j = 0; j < leny; j++)
            p[i + j] += ctoi(x[i]) * ctoi(y[j]);

    /* carry */
    for (i = 0; i < lenx + leny - 1; i++)
        if (p[i] > 9) {
            p[i + 1] += p[i] / 10;
            p[i] %= 10;
        }
}

/* ctoi: return char to int */
int ctoi(char c)
{
    return c - '0';
}

/* print: print p from high to low */
void print(int *p)
{
    int i;

    for (i = MAXD - 1; p[i] == 0 && i > 0; i--)
        ;

    for (i; i > -1; i--)
        printf("%d", p[i]);
    putchar('\n');
}

20111112

單行不定筆資料

假設每行的資料並非相同,也沒有固定,該如何處理此類問題?
例如題目要求加總每行整數的和,每一行都是一筆測資,資料數不固定。
input
1 2 3
2 3 5 7
3 3
output
6
17
6

第一種作法:先用fgets讀取整行資料,再用strtok做分解。
#include <stdio.h>
#include <string.h>

#define MAX 100

int main(void)
{
    char s[MAX];
    char *pt;
    int x, sum;

    while (fgets(s, MAX, stdin)) {
        pt = strtok(s, " ");
        sum = 0;
        while (pt) {
            sscanf(pt, "%d", &x);
            sum += x;
            pt = strtok(NULL, " ");
        }
        printf("%d\n", sum);
    }

    return 0;
}


第二種作法,是我在網路上看到的程式碼,比較直觀,也比較好實做。
利用scanf()搭配%s%c的特性,再用sscanf()處理,這種作法也是K&R的其中一題exercise。
#include <stdio.h>

#define MAX 10

int main(void)
{
    char s[MAX];
    char c;
    int x, sum;

    sum = 0;
    while (scanf("%s%c", s, &c) == 2) {
        sscanf(s, "%d", &x);
        sum += x;
        if (c == '\n') {
            printf("%d\n", sum);
            sum = 0;
        }
    }

    return 0;
}

scanf("%s%c", s, &c) == 2的意思是一次讀取一個整數(視為字串),
再加上整數後面的space或是newline。

如此,類似的題目,例如calculator,不定筆字串,皆可以用這種方式處理。

ACM 706 LC-Display

寫得滿暴力的。
關鍵在於,單單輸出一個數字時很簡單,
但是一次輸出多個數字,就是同時處理多個數字。

也就是第一行要輸出每個數字的第一行,
二行要輸出每個數字的第二行。

所以算則就是這樣,
依照數字與行數做相對應輸出。

輸出的字元可以化簡為幾種:
(1)空白
(2)最右邊為「|」
(3)最左邊為「|」
(4)最左跟最右邊為「|」
(5)中間為「-」

/* ACM 706 LC-Display
 * mythnc
 * 2011/11/12 21:54:59   
 * run time: 0.032
 */
#include <stdio.h>

#define MAXCHAR 10

void printn(char, int, int);
void space(int);
void right(int);
void middle(int);
void left(int);
void landr(int);

int main(void)
{
    char str[MAXCHAR];
    int n, i, j;

    while (scanf("%d %s", &n, str) && n != 0) {
        for (i = 0; i < 2 * n + 3; i++) {       /* line */
            for (j = 0; str[j] != '\0'; j++) {  /* number */
                if (j > 0)
                    putchar(' ');
                printn(str[j], i, n);
            }
            putchar('\n');
        }
        putchar('\n');
    }
    return 0;
}

/* printn: depend on row value and char c to do output */
void printn(char c, int row, int n)
{
    int col, head, mid, tail;

    col = n + 2;
    head = 0;
    mid = (2 * n + 3) / 2;
    tail = 2 * n + 2;   /* (2 * n + 3) - 1 */
    switch (c) {
        case '1':
            if (row == head || row == mid || row == tail)
                space(col);
            else
                right(col);
            break;
        case '2':
            if (row == head || row == mid || row == tail)
                middle(col);
            else if (row < mid)
                right(col);
            else
                left(col);
            break;
        case '3':
            if (row == head || row == mid || row == tail)
                middle(col);
            else
                right(col);
            break;
        case '4':
            if (row == head || row == tail)
                space(col);
            else if (row < mid)
                landr(col);
            else if (row == mid)
                middle(col);
            else
            right(col);
            break;
        case '5':
            if (row == head || row == mid || row == tail)
                middle(col);
            else if (row < mid)
                left(col);
            else
                right(col);
            break;
        case '6':
            if (row == head || row == mid || row == tail)
                middle(col);
            else if (row < mid)
                left(col);
            else
                landr(col);
            break;
        case '7':
            if (row == head)
                middle(col);
            else if (row == mid || row == tail)
                space(col);
            else
                right(col);
            break;
        case '8':
            if (row == head || row == mid || row == tail)
                middle(col);
            else
                landr(col);
            break;
        case '9':
            if (row == head || row == mid || row == tail)
                middle(col);
            else if (row < mid)
                landr(col);
            else
                right(col);
            break;
        case '0':
            if (row == head || row == tail)
                middle(col);
            else if (row == mid)
                space(col);
            else
                landr(col);
    }
}

/* space: print ' ' */
void space(int n)
{
    while (n--)
        putchar(' ');
}

/* right: print '|' in the rightmost */
void right(int n)
{
    int i;

    for (i = 0; i < n - 1; i++)
        putchar(' ');
    putchar('|');
}

/* middle: print '-' in middle */
void middle(int n)
{
    int i;

    putchar(' ');
    for (i = 1; i < n - 1; i++)
        putchar('-');
    putchar(' ');
}

/* left: print '|' in leftmost */
void left(int n)
{
    int i;

    putchar('|');
    for (i = 1; i < n; i++)
        putchar(' ');
}

/* landr: print '|' in leftmost and rightmost */
void landr(int n)
{
    int i;

    putchar('|');
    for (i = 1; i < n - 1; i++)
        putchar(' ');
    putchar('|');
}

ACM 530 Binomial Showdown

ACM369

/* ACM 530 Binomial Showdown
 * mythnc
 * 2011/11/12 09:39:41   
 * run time: 0.004
 */
#include <stdio.h>

#define MAXARY 50

int com(int, int);
int gcd(int, int);

int main(void)
{
    int m, n;

    while (scanf("%d %d", &n, &m) && n != 0)
        printf("%d\n", com(n, m));
    return 0;
}

/* com: return the combined times */
int com(int n, int m)
{
    int i, j, factor, tmp;
    int num[MAXARY];

    if (m == n || m == 0)
        return 1;

    if (m > n - m)
        m = n - m;
    /* init */
    for (i = 0; i < m; i++)
        num[i] = n - m + 1 + i;
    /* simplify */
    for (i = m; i > 1; i--) {
        tmp = i;
        for (j = 0; j < m; j++) {
            if (num[j] % tmp == 0) {
                num[j] /= tmp;
                break;
            }

            factor = gcd(tmp, num[j]);
            if (factor > 1) {
                tmp /= factor;
                num[j] /= factor;
            }
        }
    }
    /* product */
    for (i = 1; i < m; i++)
        num[0] *= num[i];

    return num[0];
}

/* gcd: return the gcd of a and b */
int gcd(int a, int b)
{
    while ((a %= b) && (b %= a))
        ;

    return a + b;
}

20111111

ACM 120 Stacks of Flapjacks

做sort。
雖然說是sort,但其實是做reverse。
可以稱為reverse sort嗎?

步驟:
(1)找出數列中最大值,
(2)判斷該值是否最尾端:
(a)是。數列-1。回到(1)
(b)不是。把該值做reverse移到最前端。
(3)整個數列做reverse,做完數列-1。

/* ACM 120 Stacks of Flapjacks
 * mythnc
 * 2011/11/11 19:12:46   
 * run time: 0.008
 */
#include <stdio.h>

#define MAXN 30
#define MAXS 5

void input(int *, int);
void sort(int *, int);
int findmax(int *, int);
void reverse(int *, int, int);

int main(void)
{
    int stack[MAXN];
    int count;
    char str[MAXS];
    char c;

    count = 0;
    while (scanf("%s%c", str, &c) == 2) {
        sscanf(str, "%d", &stack[count++]);
        if (c == '\n') {
            input(stack, count);
            sort(stack, count);
            printf("0\n");
            count = 0;
        }
    }
    return 0;
}

/* input: print input */
void input(int *s, int n)
{
    int i;

    printf("%d", s[0]);
    for (i = 1; i < n; i++)
        printf(" %d", s[i]);
    printf("\n");
}

/* sort: sort s in ascended */
void sort(int *s, int n)
{
    int i, max;

    for (i = n - 1; i > 0; i--) {
        max = findmax(s, i + 1);
        if (max == i)
            continue;
        if (max != 0)
            reverse(s, max, n);
        reverse(s, i, n);
    }
}

/* findmax: return the index of max element */
int findmax(int *s, int n)
{
    int i, max;

    for (i = max = 0; i < n; i++)
        if (s[i] > s[max])
            max = i;

    return max;
}

/* reverse: reverse s from [0] to [index] */
void reverse(int *s, int index, int n)
{
    int i, j, tmp;

    printf("%d ", n - index);

    for (i = 0, j = index; i < j; i++, j--) {
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}

20111110

ACM 256 Quirksome Squares

直接做。
值的平方數可以拆成兩個部份,
加總若為該值,就輸出結果。

/* ACM 256 Quirksome Squares
 * mythnc
 * 2011/11/10 16:26:49   
 * run time: 0.008
 */
#include <stdio.h>

typedef struct part {
    int front;
    int end;
} Part;

int range(int);
Part split(int, int);
void output(int, int);
int digitn(int);

int main(void)
{
    int i, digit, n;
    Part s;

    while (scanf("%d", &digit) == 1) {
            n = range(digit / 2);

        for (i = 0; i < n; i++) {
            s = split(i * i, n);
            if (s.front + s.end == i) {
                output(s.front, digit / 2);
                output(s.end, digit / 2);
                putchar('\n');
            }
        }
    }

    return 0;
}

/* range: return the square range */
int range(int max)
{
    int i, n;

    for (n = 1, i = 0; i < max; i++)
        n *= 10;

    return n;
}

/* split: split square in two parts,
 * save in s */
Part split(int square, int n)
{
    Part s;

    s.front = square / n;
    s.end = square % n;

    return s;
}

/* output: output format result */
void output(int number, int digit)
{
    int i;

    for (i = digitn(number); i < digit; i++)
        printf("0");
    printf("%d", number);
}

/* digitn: return the digit of n */
int digitn(int n)
{
    int count;

    if (n == 0)
        return 1;

    for (count = 0; n; count++)
        n /= 10;

    return count;
}

ACM 10127 Ones

大數運算。
先用python算出n從1到10000,
(有python揪甘心)
的所有digits,之後做sort,
發現到最多次digit為n = 9981,
digit為9972。
所以MAX digit設為10000。
接著就是乘除大數版,
每次都把seq的位數 + 1,
並讓seq為1111...111的形式,
計算seq % n是否整除即可。

/* ACM 10127 Ones
 * mythnc
 * 2011/11/10 10:42:16   
 * run time: 1.34
 */
#include <stdio.h>

#define MAXD  10000

void initbig(int *, int *);
int modbig(int *, int, int);
int divbig(int *, int, int *, int);
void mulbig(int *, int, int, int);
int equalbig(int *, int *, int);
void plusbig(int *, int *);

int main(void)
{
    int n, digit;
    int seq[MAXD];

    while (scanf("%d", &n) == 1) {
        initbig(seq, &digit);
        
        while (modbig(seq, digit, n) != 0)
            plusbig(seq, &digit);

        printf("%d\n", digit);
    }
    return 0;
}

/* initbig: initialzie big to 1 */
void initbig(int *seq, int *digit)
{
    seq[0] = 1;
    *digit = 1;
}

/* modbig: if seq % n == 0 return 0,
 * else return 1 */
int modbig(int *seq, int digit, int n)
{
    int q[MAXD] = { 0 };
    int qd, i;

    qd = divbig(seq, digit, q, n);
    mulbig(q, qd, digit, n);

    return equalbig(seq, q, digit);
}

/* divbig: do n divided by seq
 * return the digit of quotient */
int divbig(int *seq, int digit, int *q, int n)
{
    int i, r;

    for (r = 0, i = digit - 1; i > - 1; i--) {
        r = r * 10 + seq[i];
        q[i] = r / n;
        r %= n;
    }

    for (i = digit - 1; q[i] == 0 && i > -1; i--)
        ;

    return i + 1;
}

/* mulbig: do q * n */
void mulbig(int *q, int qd, int d, int n)
{
    int i;

    for (i = 0; i < qd; i++)
        q[i] *= n;

    /* carry */
    for (i = 0; i < d; i++)
        if (q[i] > 9) {
            q[i + 1] += q[i] / 10;
            q[i] %= 10;
        }
}

/* equalbig: if seq == q return 0
 * else return 1 */
int equalbig(int *seq, int *q, int d)
{
    int i;

    for (i = 0; i < d; i++)
        if (seq[i] != q[i])
            return 1;
    return 0;
}

/* plusbig: let the highest digit of big to be 1 */
void plusbig(int *seq, int *digit)
{
    seq[(*digit)++] = 1;
}

20111109

ACM 10057 A mid-summer night’s dream

ACM10041進階版。
一樣是求(1)最小值的median,
但還額外求(2)median存在於序列的次數,與(3)可能是median數的個數。
median的定義,如果序列是奇數個,
median為第(n + 1) / 2,但array從0開始,
即第n / 2個element,
(2)就把(1)代入,算個數,
(3)是1。

如果是偶數,定義上為第n / 2 - 1加第n / 2,
這兩個elements的和除以2。
即這兩個element的平均數。
這次時候會有兩種情況
可能兩數相等或不相等。
(A)相等
相等時,跟奇數一樣的情況
(1)為第n / 2 - 1個element
(2)用(1)代入算個數
(3)1個。

(B)不相等
不相等時,(1)還是一樣,
因為n / 2 - 1最小。
(2)就要分別用n / 2 - 1與n / 2代入,
(3)就有趣了,雖然定義偶數時median為
n / 2 - 1與n / 2的平均數,
但是事實上,從n / 2 - 1到n / 2為止,
這些數統統都是median,
不信的話可以隨便找個數列代入,
例如2 2 5 10,
2 3 4 5都是median。
(其實按照定義median是3.5,但若要求median需為整數,
2 3 4 5都會符合median定義)
個數算法為5 - 2 + 1,
所以為[n / 2] - [n / 2 - 1] + 1。
(用中括號,表示是第XXX個的意思)

n = 1000000非常大,要用malloc或全域變數。

/* ACM 10057 A mid-summer night’s dream
 * mythnc
 * 2011/11/09 17:44:48
 * run time: 0.428
 */
#include <stdio.h>
#include <stdlib.h>

int compar(const void *, const void *);
int countm(int *, int, int);

int main(void)
{
    int n, i, mid, num;
    int *seq;

    while (scanf("%d", &n) == 1) {
        seq = (int *)malloc(sizeof(int) * n);

        for (i = 0; i < n; i++)
            scanf("%d", seq + i);

        qsort(seq, n, sizeof(int), compar);

        mid = n / 2;
        if (n % 2 == 1) /* odd */
            printf("%d %d 1\n", seq[mid], countm(seq, seq[mid], n));
        else if (seq[mid] == seq[mid - 1]) /* even if same */
            printf("%d %d 1\n", seq[mid - 1], countm(seq, seq[mid - 1], n));
        else { /* if not same */
            num = countm(seq, seq[mid - 1], n) + countm(seq, seq[mid], n);
            printf("%d %d %d\n", seq[mid - 1], num, seq[mid] - seq[mid - 1] + 1);
        }
        free(seq);
    }
    return 0;
}

/* compar: for qsort */
int compar(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}

/* countm: return number of median */
int countm(int *s, int num, int n)
{
    int i, count;

    for (count = i = 0; s[i] <= num && i < n; i++)
        if (s[i] == num)
            count++;

    return count;
}

ACM 10041 Vito's family

一開始算mean,
立刻得到WA。
滿腦子充滿問號……

結論是:要算median,
而非mean,
當資料是對稱時算average,才能用mean,
若資料是偏斜的,算average要用median。
這篇有解釋兩者的差別。
舉個例子,若資料是10 50 99 100 101,
median是99,mean是72,
最短距離分別是141跟168,
所以要用median,而不是用mean。

/* ACM 10041 Vito's family
 * mythnc
 * 2011/11/09 15:57:38
 * run time: 0.024
 */
#include <stdio.h>
#include <stdlib.h>

#define MAXR 499

int compare(const void *, const void *);

int main(void)
{
    int r[MAXR];
    int n, sum, i, median, mid;
    
    scanf("%*d");
    while (scanf("%d", &n) == 1) {
        for (i = 0; i < n; i++)
            scanf("%d", r + i);

        qsort(r, n, sizeof(int), compare);
        mid = n / 2;
        if (n % 2 == 1)
            median = r[mid];
        else
            median = (r[mid] + r[mid - 1]) / 2;
        for (sum = i = 0; i < n; i++)
            if (median < r[i])
                sum += r[i] - median;
            else
                sum += median - r[i];

        printf("%d\n", sum);
    }
    return 0;
}

int compare(const void *a, const void *b)
{
    return *(int *)a - *(int *)b;
}

ACM 10469 To Carry or not to Carry

嗯……算XOR。
就是這樣……

/* ACM 10469 To Carry or not to Carry
 * mythnc
 * 2011/11/09 15:34:01   
 * run time: 0.012
 */
#include <stdio.h>
 
int main(void)
{
    unsigned int a, b;
 
    while (scanf("%u %u", &a, &b) == 2)
        printf("%u\n", a ^ b);
    return 0;
}

ACM 151 Power Crisis

一開始的想法:
難道是弄個array然後一個一個慢慢數?
好笨的方法……
結果看來也沒其他方法 orz。

由於覺得有別的方法,
於是就用array + linklist的寫法解,
當然指標是很會飄的(抖)。

不過看來我的解法也是一個一個慢慢數,囧。

在網路上看到幾個151的AC code,
不過有些在n = 14時,答案都錯,
看來測資沒有n = 14這組 =w=。

/* ACM 151 Power Crisis
 * mythnc
 * 2011/11/09 10:55:26   
 * run time: 0.004
 */
#include <stdio.h>

#define MAXN 99

typedef struct list {
    int i;
    struct list *next;
    struct list *pre;
} List;

void init(List *array, int n);
int findm(List *p, int n);
void link(List *p, int n);

int main(void)
{
    List array[MAXN];
    int n;

    while (scanf("%d", &n) && n != 0) {
        init(array, n);
        printf("%d\n", findm(array, n));
    }
    return 0;
}

/* init: initialize array */
void init(List *array, int n)
{
    int i;

    for (i = 0; i < n; i++)
        array[i].i = i + 1;
}

/* findm: find and return the number m */
int findm(List *ary, int n)
{
    int count, i, m;
    List *p;

    for (m = 1; ; m++) {  /* find m */
        link(ary, n);     /* link all again */
        p = ary;
        count = 1;
        while (count < n) {
            p->pre->next = p->next;  /* link arrange */
            p->next->pre = p->pre;
            for (i = 0; i < m; i++)  /* move */
                p = p->next;
            count++;
            if (p->i == 13) {
                if (count == n)
                    return m;
                break;
            }
        }
    }
}

/* link: link array elements one by one
 * in a circle */
void link(List *p, int n)
{
    int i;

    i = 0;
    p[i].next = &p[i + 1];
    p[i].pre = &p[n - 1];
    for (i = 1; i < n - 1; i++) {
        p[i].next = &p[i + 1];
        p[i].pre = &p[i - 1];
    }
    p[i].next = &p[0];
    p[i].pre = &p[i - 1];
}

20111108

USACO Palindromic Squares

印出平方次為回文的數字與該平方,
有趣的題目。
跟上一題一樣,可以一次一個慢慢判斷平方次,
也可以一次判斷完300個平方。
竟然是回文,最中間的數就不用判斷,
也不用作reverse,倒是數字輸出要reverse。
數字跟平方數都要依照base去做輸出。

/*
ID: mythnc2
LANG: C
TASK: palsquare
Palindromic Squares
2011/11/08 11:09:53   
*/
#include <stdio.h>
#include <string.h>

#define MAXN    300
#define MAXCHAR 20
#define TRUE    1
#define FALSE   0

void conversion(int, int, char *);
void reverse(char *);
int pal(char *);

int main (void)
{
    FILE *fin, *fout;
    int base, i;
    char trans[MAXCHAR];
    char number[MAXCHAR];

    fin = fopen("palsquare.in", "r");
    fout = fopen("palsquare.out", "w");

    fscanf(fin, "%d", &base);

    for (i = 0; i < MAXN; i++) {
        conversion(base, (i + 1) * (i + 1), trans);
        /* output */
        if (pal(trans)) {
            conversion(base, i + 1, number);
            reverse(number);
            fprintf(fout, "%s %s\n", number, trans);
        }
    }
    return 0;
}

/* conversion: conver n in base of b save in t */
void conversion(int b, int n, char *t)
{
    int i, mod;
    char map[] = "0123456789ABCDEFGHIJ";

    /* n conversion */
    for (i = 0; n; i++) {
        t[i] = map[n % b];
        n /= b;
    }
    t[i] = '\0';
}

/* reverse: reverse string s */
void reverse(char *s)
{
    int i, j;
    char tmp;
    
    for (i = 0, j = strlen(s) - 1; i < j; i++, j--) {
        tmp = s[i];
        s[i] = s[j];
        s[j] = tmp;
    }
}

/* pal: return TRUE if array t is palindrome,
 * else return FALSE */
int pal(char *t)
{
    int i, j;

    for (i = 0, j = strlen(t) - 1; i < j; i++, j--)
        if (t[i] != t[j])
            return FALSE;

    return TRUE;
}

ACM 694 The Collatz Sequence

ACM100類似題。
找次數小於等於limit即可。

/* ACM 694 The Collatz Sequence
 * mythnc
 * 2011/11/08 10:21:28   
 * run time: 0.056
 */
#include <stdio.h>

int times(long long , int);

int main(void)
{
    int a, limit, set;

    set = 0;
    while (scanf("%d %d", &a, &limit)
           && a > 0
           && limit > 0)
        printf("Case %d: A = %d, limit = %d, number of terms = %d\n",
               ++set, a, limit, times(a, limit));

    return 0;
}

/* times: return the term number of n */
int times(long long n, int limit)
{
    int count;

    count = 1;
    while (n != 1) {
        if (n % 2 == 1) {
            n = 3 * n + 1;
            if (n > limit)
                break;
        }
        else
            n >>= 1;
        count++;
    }

    return count;
}

ACM 10812 Beat the Spread!

二元一次方程整數解。
忘記寫return 0吃了幾次RE,
真妙……

/* ACM 10812 Beat the Spread!
 * mythnc
 * 2011/11/08 09:29:40   
 * run time: 0.004
 */
#include <stdio.h>

void output(int, int);

int main(void)
{
    int f1, f2;

    scanf("%*d");
    while (scanf("%d %d", &f1, &f2) == 2)
        output(f1, f2);
    return 0;
}

/* output: output result */
void output(int f1, int f2)
{
    int x, y;

    if ((f1 + f2) % 2 != 0) {
        printf("impossible\n");
        return;
    }

    x = (f1 + f2) / 2;
    if (x < 0) {
        printf("impossible\n");
        return;
    }
    y = f1 - x;
    if (y < 0)
        printf("impossible\n");
    else if (x > y)
        printf("%d %d\n", x, y);
    else
        printf("%d %d\n", y, x);
}

20111107

USACO Name That Number

第一次遇到開檔問題……
把字典的字母轉成數字並做排序,
出現Q或Z不做轉換。
再把輸入檔的數字,
從字典檔裡做match,
找到就可以output。

本來想用qsort,但是數字相同時,
qsory會重排,所以只好自己寫個sort。

不過這種方法好笨啊!
寫完看到它的分析才知道,
反過來做比較快!
直接從輸入檔的數字,
跟字典的字母做比較,
比較時才把字母轉成數字,
發現沒match,就再找下一個字母,
直到找到為止。

不過這兩種方法有好有壞……
像我就是一次先弄完,之後輸入的數字就可以直接找。
它的作法是每次都從字典的開頭往後找。

不過這題,因為輸入檔只有一筆數字,
所以用它的方法滿不錯的。
資料多筆的話就未必囉!

這大概是USACO跟UVA最大差異,
測資的處理方式不同。

/*
ID: mythnc2
LANG: C
TASK: namenum
Name That Number
2011/11/07 21:10:16   
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXN    5000
#define MAXCHAR 12
#define TRUE    1
#define FALSE   0

typedef struct name {
    long long number;
    char name[MAXCHAR];
} Name;

int screen(char *);
void copy(Name *, char *);
void sort(Name *, int);
int cton(char);
int find(long long, Name *, int);
void printout(FILE *, int, Name *, int);

int main (void)
{
    FILE *fin, *fout, *fdict;
    char str[MAXCHAR + 1];
    Name cow[MAXN];
    int count, index;
    long long serial;

    fin = fopen("namenum.in", "r");
    fout = fopen("namenum.out", "w");
    fdict = fopen("dict.txt", "r");

    count = 0;
    while (fscanf(fdict, "%s", str) != EOF) {
        if (screen(str))
            continue;
        copy(&cow[count++], str);
        sort(cow, count);
    }

    fscanf(fin, "%lld", &serial);

    if ((index = find(serial, cow, count)) > -1)
        printout(fout, index, cow, count);
    else
        fprintf(fout, "NONE\n");

    return 0;
}

/* screen: if letter has Q or Z,
 * jump over it */
int screen(char *s)
{
    for (; *s != '\0'; s++)
        if (*s == 'Q' || *s == 'Z')
            return TRUE;

    return FALSE;
}

/* copy: copy the letter and number of s
 * to cow */
void copy(Name *cow, char *s)
{
    int i;

    /* copy letters */
    strcpy(cow->name, s);
    /* make letter to number */
    for (cow->number = i = 0; s[i] != '\0'; i++) {
        if (i > 0)
            cow->number *= 10;
        cow->number += cton(s[i]);
    }
}

/* sort: insertion sort array cow */
void sort(Name *cow, int n)
{
    int i;
    Name tmp;

    if (n < 2)
        return;

    tmp = cow[n - 1];
    for (i = n - 2; i > -1; i--)
        if (cow[i].number > tmp.number) {
            cow[i + 1] = cow[i];
            if (i == 0)
                cow[i] = tmp;
        }
        else {
            cow[i + 1] = tmp;
            break;
        }
}

/* cton: cast char to number */
int cton(char c)
{
    char letter[24] = {'A', 'B', 'C',
                       'D', 'E', 'F',
                       'G', 'H', 'I',
                       'J', 'K', 'L',
                       'M', 'N', 'O',
                       'P', 'R', 'S',
                       'T', 'U', 'V',
                       'W', 'X', 'Y'};
    int i;

    for (i = 0; i < 24; i++)
        if (c == letter[i])
            return 2 + i / 3;
}


/* find: find number in array cow
 * if find return index,
 * else return -1 */
int find(long long number, Name *cow, int n)
{
    int head, mid, tail;

    head = 0;
    tail = n - 1;
    while (head <= tail) {
        mid = (head + tail) / 2;
        if (cow[mid].number < number)
            head = mid + 1;
        else if (cow[mid].number > number)
            tail = mid - 1;
        else
            return mid;
    }

    return -1;
}

/* printout: print out result */
void printout(FILE *f, int i, Name *cow, int n)
{
    /* find the first same value number */
    while (cow[i - 1].number == cow[i].number && i - 1 >= 0)
        i--;
    /* print out */
    fprintf(f, "%s\n", cow[i].name);
    while (cow[i + 1].number == cow[i].number && i + 1 < n) {
        i++;
        fprintf(f, "%s\n", cow[i].name);
    }
}

ACM 686 Goldbach's Conjecture (II)

ACM543
這次是找pair數。
n = 4要另外處理。
其他的從3開始算到n / 2即可。

/* ACM 686 Goldbach's Conjecture (II)
 * mythnc
 * 2011/11/07 17:45:42   
 * run time: 0.016
 */
#include <stdio.h>

#define TRUE  1
#define FALSE 0

int countp(int);
int prime(int);

int main(void)
{
    int n;

    while (scanf("%d", &n) && n != 0)
        printf("%d\n", countp(n));
    return 0;
}

/* countp: return the pair numbers match
 * Goldbach's Conjecture */
int countp(int n)
{
    int i, count;

    if (n == 4)
        return 1;

    for (count = 0, i = 3; 2 * i <= n; i += 2)
        if (prime(i) && prime(n - i))
            count++;

    return count;
}

/* prime: return TRUE if n is prime,
 * else return FALSE */
int prime(int n)
{
    int i;

    for (i = 3; i * i <= n; i += 2)
        if (n % i == 0)
            return FALSE;

    return TRUE;
}

ACM 401 Palindromes

迴文跟鏡像。
迴文做word reverse,
鏡像先word reverse再letter reverse。

/* ACM 401 Palindromes
 * mythnc
 * 2011/11/07 16:22:59   
 * run time: 0.016
 */
#include <stdio.h>
#include <string.h>

#define MAXCHAR 21
#define TRUE    1
#define FALSE   0

int reverse(char *, char *);
int mirror(char *, char *);
int valid(char, char *, int);

int main(void)
{
    char str[MAXCHAR], t[MAXCHAR];

    while (scanf("%s", str) != EOF)
        if (reverse(str, t))
            if (mirror(str, t))
                printf("%s -- is a mirrored palindrome.\n\n", str);
            else
                printf("%s -- is a regular palindrome.\n\n", str);
        else
            if (mirror(str, t))
                printf("%s -- is a mirrored string.\n\n", str);
            else
                printf("%s -- is not a palindrome.\n\n", str);
    return 0;
}

/* reverse: save the reverse of s in t,
 * if t and s are palindrome to each other,
 * return TRUE, else return FALSE */
int reverse(char *s, char *t)
{
    int i, j;

    for (i = 0, j = strlen(s) - 1; i < strlen(s); i++, j--)
        t[i] = s[j];
    t[i] = '\0';

    if (strcmp(s, t) == 0)
        return TRUE;
    return FALSE;
}

/* mirror: if s is a mirror string
 * return TRUE, else return FALSE */
int mirror(char *s, char *t)
{
    char map[21] = {'A', 'E', 'H', 'I', 'J', 'L', 'M', 'O', 'S', 'T',
                    'U', 'V', 'W', 'X', 'Y', 'Z', '1', '2', '3', '5',
                    '8'};
    char key[21] = {'A', '3', 'H', 'I', 'L', 'J', 'M', 'O', '2', 'T',
                    'U', 'V', 'W', 'X', 'Y', '5', '1', 'S', 'E', 'Z',
                    '8'};
    char m[MAXCHAR];
    int index, i;

    for (i = 0; i < strlen(t); i++)
        if ((index = valid(t[i], map, 21)) >= 0)
            m[i] = key[index];
        else
            return FALSE;
    m[i] = '\0';

    if (strcmp(s, m) == 0)
        return TRUE;
    return FALSE;
} 

/* valid: return the index of char c in map,
 * if c is a valid char, else return -1 */
int valid(char c, char *map, int n)
{
    int i;

    for (i = 0; i < n; i++)
        if (c == map[i])
            return i;

    return -1;
}

ACM 495 Fibonacci Freeze

一開始以為很簡單,就算出費氏,
結果n = 5000時,數字根本超大,
心機啊……

像這題array這麼大的,不能設成區域變數,
要不然會stack overflow,
要用全域變數或malloc。

最後寫出來了,沒想到一直RE RE RE RE,
哇咧,原來費氏數列要從0開始,
難怪一直RE XD,
真蠢我也 orz。

/* ACM 495 Fibonacci Freeze
 * mythnc
 * 2011/11/07 11:53:16   
 * run time: 0.532
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXARY 1100
#define MAXN   5001

void init(int **);
void fibo(int **);
int bigadd(int *, int *, int *, int);
void printbig(int *);
void freen(int **);

int main(void)
{
    int n;
    int *number[MAXN];

    init(number);
    fibo(number);
    while (scanf("%d", &n) == 1) {
        printf("The Fibonacci number for %d is ", n);
        printbig(number[n]);
    }
    freen(number);
    return 0;
}

/* init: make space to n[i] and 
 * initialize content of n[i] to zero */
void init(int **n)
{
    int i;

    for (i = 0; i < MAXN; i++) {
        n[i] = (int *)malloc(sizeof(int) * MAXARY);
        memset(n[i], 0, sizeof(int) * MAXARY);
    }
}

/* fibo: calculate fibonacci number from 0 to 5000 */
void fibo(int **n)
{
    int i, digit;

    n[0][0] = 0;
    n[1][0] = digit = 1;
    for (i = 2; i < MAXN; i++)
        digit = bigadd(n[i], n[i - 1], n[i - 2], digit);

}

/* bigadd: big number addtion,
 * return it's digits */
int bigadd(int *n, int *pre, int *ppre, int d)
{
    int i;

    for (i = 0; i < d; i++)
        n[i] += pre[i] + ppre[i];

    /* carry */
    for (i = 0; i < d; i++)
        if (n[i] > 9) {
            n[i] %= 10;
            n[i + 1]++;
        }

    if (n[i] != 0)
        return i + 1;
    return i;
}

/* printbig: print out big number */
void printbig(int *n)
{
    int i;

    i = MAXARY - 1;
    while (n[i] == 0 && i > 0)
        i--;
    for (; i > -1; i--)
        printf("%d", n[i]);
    printf("\n");
}

void freen(int **n)
{
    int i;

    for (i = 0; i < MAXN; i++)
        free(n[i]);
}

ACM 10019 Funny Encryption Method

進位轉換。
10 -> 2,找1的次數,
16 -> 10 -> 2,找1的次數。

/* ACM 10019 Funny Encryption Method
 * mythnc
 * 2011/11/07 11:36:18   
 * run time: 0.004
 */
#include <stdio.h>

int dectobin(int);
int hextodec(int);

int main(void)
{
    int m;

    scanf("%*d");
    while (scanf("%d", &m) == 1)
        printf("%d %d\n", dectobin(m),
                dectobin(hextodec(m)));
    return 0;
}

/* dectobin: dec number to binary number,
 * return 1's times */
int dectobin(int m)
{
    int r, count;

    count = 0;
    while (m) {
        r = m % 2;
        if (r)
            count++;
        m /= 2;
    }

    return count;
}

/* hextodec: return the number in hex */
int hextodec(int m)
{
    int h, r, times, i;

    h = times = 0;
    while (m) {
        r = m % 10;
        for (i = 0; i < times; i++)
            r *= 16;
        h += r;
        times++;
        m /= 10;
    }

    return h;
}

ACM 10050 Hartals

算罷工日。
五六兩天不算。
先把罷工參數做sort,
若出現倍數情況,就不儲存該參數。
(例如已有2,又出現4,4 % 2 = 0,
4就不列入)
接著再做天數紀錄,
最後計算天數即可。

/* ACM 10050 Hartals
 * mythnc
 * 2011/11/06 22:57:42   
 * run time: 0.020
 */
#include <stdio.h>

#define MAXDAY 3650
#define MAXPTY 100
#define TRUE   1
#define FALSE  0

int hartal(int *, int);
void sort(int *, int, int);
int loseday(int *, int, int *, int);
int countday(int *, int);

int main(void)
{
    int day[MAXDAY] = { FALSE };
    int party[MAXPTY];
    int set, nd, np;

    scanf("%d", &set);
    while (set--) {
        scanf("%d", &nd);
        scanf("%d", &np);
        np = hartal(party, np);
        printf("%d\n", loseday(day, nd, party, np));
    }
    return 0;
}

/* hartal: check hartal number can be mod by
 * other number or not only receive hartal
 * number when it can't be mod by other numbers */
int hartal(int *p, int n)
{
    int count, i, j, tmp, rec;

    for (count = i = 0; i < n; i++) {
        scanf("%d", &tmp);
        for (rec = TRUE, j = 0; j < count; j++)
            if (tmp % p[j] == 0) {
                rec = FALSE;
                break;
            }
        if (rec) {
            sort(p, tmp, ++count);
        }
    }

    return count;
}

/* sort: insertion sort hartal number */
void sort(int *p, int number, int n)
{
    int i;

    if (n == 1) {
        p[0] = number;
        return;
    }

    for (i = n - 2; i > -1; i--)
        if (p[i] > number) {
            p[i + 1] = p[i];
            if (i == 0)
                p[0] = number;
        }
        else {
            p[i + 1] = number;
            break;
        }
}

/* loseday: find the lose day */
int loseday(int *d, int nd, int *p, int np)
{
    int i, j;

    for (i = 0; i < np; i++)
        for (j = p[i]; j < nd + 1; j += p[i])
            if (j % 7 != 0 && j % 7 != 6 && !d[j])
                d[j] = TRUE;

    return countday(d, nd);
}

/* countday: initalize value to zero and 
 * return sum of hartal days */
int countday(int *d, int nd)
{
    int i, sum;

    for (sum = 0, i = 1; i < nd + 1; i++)
        if (d[i]) {
            d[i] = FALSE;  /* initialize value to 0 */
            sum++;
        }

    return sum;
}

20111106

ACM 499 What's The Frequency, Kenneth?

找最大值。
直接做。

/* ACM 499 What's The Frequency, Kenneth?
 * mythnc
 * 2011/11/06 22:05:39   
 * run time: 0.044
 */
#include <stdio.h>

#define MAXARY 52

void printout(int *);
void init(int *);

int main(void)
{
    int letter[MAXARY] = { 0 };
    int c;

    while ((c = getchar()) != EOF) {
        if (c >= 'A' && c <= 'Z')
            letter[c - 'A']++;
        else if (c >= 'a' && c <= 'z')
            letter[c - 'a' + 26]++;
        else if (c == '\n') {
            printout(letter);
            init(letter);
        }
    }
    return 0;
}

/* printout: print out the max letters */
void printout(int *p)
{
    int i, max;

    /* find the element which has max value */
    for (i = max = 0; i < MAXARY; i++)
        if (p[max] < p[i])
            max = i;

    /* output */
    for (i = 0; i < MAXARY; i++)
        if (p[i] == p[max] && i < 26)
            printf("%c", 'A' + i);
        else if (p[i] == p[max] && i >= 26)
            printf("%c", 'a' + i - 26);
    printf(" %d\n", p[max]);
}

/* init: initialize array to zero */
void init(int *p)
{
    int i;

    for (i = 0; i < MAXARY; i++)
        p[i] = 0;
}

20111104

USACO Transformations

直接做。
果然是個complete search,
也只能直接做。

/*
ID: mythnc2
LANG: C
TASK: transform
2011/11/04 22:41:28   
Transformations
*/
#include <stdio.h>

#define MAXN 10
#define TRUE  1
#define FALSE 0

int menu(char (*)[], char (*)[], int);
int de90(char (*)[], char (*)[], int);
int de180(char (*)[], char (*)[], int);
int de270(char (*)[], char (*)[], int);
void reflect(char (*)[], char (*)[], int);
int equal(char (*)[], char (*)[], int);

int main (void)
{
    FILE *fin, *fout;
    int n, i;
    char sq[MAXN][MAXN + 1], trans[MAXN][MAXN + 1];

    fin = fopen("transform.in", "r");
    fout = fopen("transform.out", "w");

    fscanf(fin, "%d", &n);
    for (i = 0; i < n; i++)
        fscanf(fin, "%s", sq[i]);
    for (i = 0; i < n; i++)
        fscanf(fin, "%s", trans[i]);
    fprintf(fout, "%d\n", menu(sq, trans, n));
    return 0;
}

/* menu: return one of the possible transformation */
int menu(char (*sq)[MAXN + 1], char (*trans)[MAXN + 1], int n)
{
    char mirror[MAXN][MAXN + 1];

    if (de90(sq, trans, n))
        return 1;

    if (de180(sq, trans, n))
        return 2;

    if (de270(sq, trans, n))
        return 3;

    reflect(sq, mirror, n);
    if (equal(mirror, trans, n))
        return 4;

    if (de90(mirror, trans, n) || de180(mirror, trans, n)
        || de270(mirror, trans, n))
        return 5;

    if (equal(sq, trans, n))
        return 6;

    return 7;
}

/* de90: if sq rotate 90 degree is trans return True */
int de90(char (*sq)[MAXN + 1], char (*trans)[MAXN + 1], int n)
{
    int i, j;

    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            if (sq[i][j] != trans[j][n - 1 - i])
                return FALSE;

    return TRUE;
}

/* de180: if sq rotate 180 degree is trans return True */
int de180(char (*sq)[MAXN + 1], char (*trans)[MAXN + 1], int n)
{
    int i, j;

    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            if (sq[i][j] != trans[n - 1 - i][n - 1 - j])
                return FALSE;

    return TRUE;
}

/* de270: if sq rotate 270 degree is trans return True */
int de270(char (*sq)[MAXN + 1], char (*trans)[MAXN + 1], int n)
{
    int i, j;

    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            if (sq[i][j] != trans[n - 1 - j][i])
                return FALSE;

    return TRUE;
}

/* reflect: copy the reflection of sq to mirror */
void reflect(char (*sq)[MAXN + 1], char (*mirror)[MAXN + 1], int n)
{
    int i, j;

    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            mirror[i][n - 1 - j] = sq[i][j];
}

/* equal: if sq is same as trans return True */
int equal(char (*sq)[MAXN + 1], char (*trans)[MAXN + 1], int n)
{
    int i, j;

    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            if (sq[i][j] != trans[i][j])
                return FALSE;

    return TRUE;
}

ACM 10107 What is the Median?

找中位數。
應該insertion sort最快吧?
所以就用insertion sort了

/* ACM 10107 What is the Median? 
 * mythnc
 * 2011/11/04 19:16:36   
 * run time: 0.040
 */
#include <stdio.h>

#define MAXN 10000

void sort(int *, int);
int median(int *, int);

int main(void)
{
    int n, count;
    int seq[MAXN];

    count = 0;
    while (scanf("%d", &n) == 1) {
        seq[count++] = n;
        if (count > 1)
            sort(seq, count);
        printf("%d\n", median(seq, count));
    }

    return 0;
}

/* sort: insertion sort array s */
void sort(int *s, int n)
{
    int i, tmp;

    tmp = s[n - 1];
    for (i = n - 2; i > -1; i--)
        if (s[i] > tmp) {
            s[i + 1] = s[i];
            if (i == 0)
                s[0] = tmp;
        }
        else {
            s[i + 1] = tmp;
            break;
        }
}

/* median: return the median number */
int median(int *s, int n)
{
    int k;

    k = n / 2;
    if (n % 2 == 1)
        return s[k];
    else
        return (s[k] + s[k - 1]) / 2;
}

ACM 673 Parentheses Balance

之前寫DS也處理過括號問題,
不過當時是用很笨的方法。
就是先找第一個右括號,
再去找跟它相對應的左括號,
如果match就消除為空白,
沒match就是有少括號或是括號錯誤。
一直重複這個動作,直到整個string變為空白為止,
就是全都有pair……

實際上,根本不是這樣寫!
太笨太複雜了!
根本只要用stack就能解了,囧。

所以括號跟四則運算都能用stack處理……(筆記)

/* ACM 673 Parentheses Balance
 * mythnc
 * 2011/11/04 18:37:08   
 * run time: 0.024
 */
#include <stdio.h>

#define MAXCHAR 130
#define YES     1
#define NO      0

int pair(char *);

int main(void)
{
    int n;
    char s[MAXCHAR];

    scanf("%d\n", &n);
    while (n--) {
        fgets(s, MAXCHAR, stdin);
        if (pair(s) == YES)
            printf("Yes\n");
        else
            printf("No\n");
    }

    return 0;
}

/* pair: if () or [] is pair return YES,
 * else return NO */
int pair(char *s)
{
    int i, count;
    char stack[MAXCHAR];

    for (count = i = 0; s[i] != '\n'; i++)
        if (s[i] == '(' || s[i] == '[')
            stack[count++] = s[i];
        else if (s[i] == ')') {
            if (count == 0 || stack[--count] != '(')
                return NO;
        }
        else if (s[i] == ']')
            if (count == 0 || stack[--count] != '[')
                return NO;

    if (count == 0)
        return YES;
    else
        return NO;
}

ACM 543 Goldbach's Conjecture

wiki可知,
Goldbach's conjecture到4 * 10^18都是對的,
所以在1000000的範圍內,不會有Goldbach's conjecture is wrong的output。
所以就從3, 5, 7, ...一直往上找,一定會存在一組質數使得n = prime1 + prime2。

/* ACM 543 Goldbach's Conjecture
 * mythnc
 * 2011/11/04 15:28:29   
 * run time: 0.164
 */
#include <stdio.h>

#define TRUE  1
#define FALSE 0

int prime(int);

int main(void)
{
    int n, i;

    while (scanf("%d", &n) && n != 0)
        for (i = 3; i < n; i += 2)
            if (prime(i) == TRUE && prime(n - i) == TRUE) {
                printf("%d = %d + %d\n", n, i, n - i);
                break;
            }

    return 0;
}

/* prime: if n is prime, return TRUE,
 * else return FALSE */
int prime(int n)
{
    int i;

    for (i = 3; i * i <= n; i += 2)
        if (n % i == 0)
            return FALSE;

    return TRUE;
}

ACM 10079 Pizza Cutting

最多塊pizza的切法:
第一刀要切到1塊,sum = 2
第二刀要切到2塊,sum = 2 + 2
第三刀要切到3塊,sum = 2 + 2 + 3
第四刀要切到4塊,sum = 2 + 2 + 3 + 4
第五刀要切到5塊,sum = 2 + 2 + 3 + 4 + 5
……
老實說腦袋是有卡到。

/* ACM 10079 Pizza Cutting
 * mythnc
 * 2011/11/04 14:49:55   
 * run time: 0.016
 */
#include <stdio.h>

int main(void)
{
    long long n;

    while (scanf("%lld", &n) && n >= 0)
        printf("%lld\n", n * (1 + n) / 2 + 1);
    return 0;
}

20111102

ACM 488 Triangle Wave

印三角形跟次數,
想當初第一次解這種題目還會卡住……
果然人都是從新手開始的!

/* ACM 488 Triangle Wave
 * mythnc
 * 2011/11/02 21:48:29   
 * run time: 0.44
 */
#include <stdio.h>

void triangle(int);

int main(void)
{
    int height, time, set, i;

    scanf("%*d");
    set = 0;
    while (scanf("%d %d", &height, &time) == 2) {
        if (set > 0)
            printf("\n");
        for (i = 0; i < time; i++) {
            if (i > 0)
                printf("\n");
            triangle(height);
        }
        set++;
    }
    return 0;
}

/* triangle: print out triangle */
void triangle(int h)
{
    int i, j;

    for (i = 1; i < h + 1; i++) {
        for (j = 0; j < i; j++)
            printf("%d", i);
        printf("\n");
    }

    for (i = h - 1; i > 0; i--) {
        for (j = i - 1; j > -1; j--)
            printf("%d", i);
        printf("\n");
    }
}

ACM 10346 Peter’s Smokes

捲香煙……
算除法跟餘數。
每次除完的餘數,
會影響下一次的除法結果,
所以餘數要紀錄下來。

/* ACM 10346 Peter’s Smokes
 * mythnc
 * 2011/11/02 20:18:09   
 * run time: 0.008
 */
#include <stdio.h>

int rollcig(int, int);

int main(void)
{
    int n, k;

    while (scanf("%d %d", &n, &k) == 2)
        printf("%d\n", rollcig(n, k));

    return 0;
}

/* rollcig: return the cigarette peter have */
int rollcig(int n, int k)
{
    int count, r;
    
    for (count = n; n >= k; n += r) {
        r = n % k;
        n /= k;
        count += n;
    }

    return count;
}

20111101

ACM 160 Factors and Factorials

質因數分解,階層版。
題目只要求到100!,
就偷懶一下。
先找出小於100的質數,
再做找質因數的動作。

/* ACM 160 Factors and Factorials
 * mythnc
 * 2011/11/01 20:15:27   
 * run time: 0.008
 */
#include <stdio.h>
 
#define MAXP 25
 
void init(int *);
void factor(int, int *, int *);
void printout(int, int *, int);
int size(int *);
 
int main(void)
{
    int n;
    int prime[] = { 2,  3,  5,  7, 11, 13, 17, 19, 23, 29,
                   31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
                   73, 79, 83, 89, 97};
    int map[MAXP];
 
    while (scanf("%d", &n) && n != 0) {
        init(map);
        factor(n, prime, map);
        printout(n, map, size(map));
    }
    return 0;
}
 
/* init: initialize array m to zero */
void init(int *m)
{
    int i;
 
    for (i = 0; i < MAXP; i++)
        m[i] = 0;
}
 
/* factor: find prime factors */
void factor(int n, int *p, int *map)
{
    int i, j, tmp;
 
    for (i = 2; i < n + 1; i++) {
        tmp = i;
        for (j = 0; p[j] <= tmp; j++)
            while (tmp % p[j] == 0) {
                map[j]++;
                tmp /= p[j];
            }
    }
}
 
/* size: return the prime factors array m have */
int size(int *m)
{
    int i;
 
    for (i = MAXP - 1; m[i] == 0; i--)
        ;
 
    return i + 1;
}
 
/* printout: print out results */
void printout(int n, int *m, int count)
{
    int i;
 
    printf("%3d! =", n);
    for (i = 0; i < count; i++) {
        if (i == 15)
            printf("\n%6c", ' ');
        printf("%3d", m[i]);
    }
    printf("\n");
}

ACM 11172 Relational Operators

判斷大小,
直接做。

/* ACM 11172 Relational Operators
 * mythnc
 * 2011/11/01 18:35:45   
 * run time: 0.008
 */
#include <stdio.h>
 
int main(void)
{
    int a, b;

    scanf("%*d");
    while (scanf("%d %d", &a, &b) == 2)
        if (a > b)
            printf(">\n");
        else if (a == b)
            printf("=\n");
        else
            printf("<\n");
 
    return 0;
}