20120118

ACM 507 Jill Rides Again

maximum sum problem。
一樣用kadane去解。
不過不太一樣的是要注意sum == max的情況,
要找最大範圍的起始點 + 終點。

/* ACM 507 Jill Rides Again
 * mythnc
 * 2012/01/18 11:15:29   
 * run time: 0.136
 */
#include <stdio.h>

#define MAXS 20001

void input(void);
void kadane(void);
void output(int);

int list[MAXS];
int n, maxstart, maxend;

int main(void)
{
    int set, i;

    scanf("%d", &set);
    for (i = 1; i <= set; i++) {
        input();
        kadane();
        output(i);
    }

    return 0;
}

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

    scanf("%d", &n);
    for (i = 1; i < n; i++)
        scanf("%d", &list[i]);
}

/* kadane: use kadane algorithm to find the maximum sum */
void kadane(void)
{
    int max, start, end;
    int sum;

    max = 0;
    maxstart = maxend = sum = 0;
    start = 1;
    for (end = 1; end < n; end++) {
        sum += list[end];
        if (sum > max) {
            max = sum;
            maxstart = start;
            maxend = end;
        }
        else if (sum == max && end - start > maxend - maxstart) {
            maxstart = start;
            maxend = end;
        }
        if (sum < 0) {
            sum = 0;
            start = end + 1;
        }
    }
}

/* output: out put result */
void output(int set)
{
    if (maxstart == 0)
        printf("Route %d has no nice parts\n", set);
    else
        printf("The nicest part of route %d is between stops %d and %d\n",
               set, maxstart, maxend + 1);
}

20120117

ACM 11137 Ingenuous Cubrency

DP。
ACM674

/* ACM 11137 Ingenuous Cubrency
 * mythnc
 * 2012/01/17 21:40:44   
 * run time: 0.032
 */
#include <stdio.h>

#define MAXN 10000
#define MAXC 21

int main(void)
{
    int coin[MAXC] = {1, 8, 27, 64, 125, 216,
                    343, 512, 729, 1000, 1331, 1728,
                    2197, 2744, 3375, 4096, 4913, 5832,
                    6859, 8000, 9261};
    long long dp[MAXN] = { 1 };
    int i, j, money;

    for (i = 0; i < MAXC; i++)
        for (j = coin[i]; j < MAXN; j++)
            dp[j] += dp[j - coin[i]];

    while (scanf("%d", &money) == 1)
        printf("%lld\n", dp[money]);

    return 0;
}

20120116

ACM 497 Strategic Defense Initiative

一樣是Longest Increasing Subsequence……
結果用ACM481的方法去解竟然WA,囧rz。
用正常O(n ^ 2)解就AC……大概是我方法哪裡不對吧,
然後ACM481剛剛好AC……無解!

/* ACM 497 Strategic Defense Initiative
 * mythnc
 * 2012/01/16 20:42:20   
 * run time: 0.016
 */
#include <stdio.h>

#define MAXN    100000
#define LINEMAX 50

void input(void);
void lis(void);

int n;
int seq[MAXN], len[MAXN], pre[MAXN];

int main(void)
{
    int set, i;

    scanf("%d", &set);
    getchar();
    getchar();
    for (i = 0; i < set; i++) {
        input();
        if (i > 0)
            putchar('\n');
        lis();
    }

    return 0;
}

/* input: receive input data */
void input(void)
{
    char line[LINEMAX];

    n = 0;
    while (fgets(line, LINEMAX, stdin) && line[0] != '\n')
        sscanf(line, "%d", &seq[n++]);
}

/* lis: find lis and output */
void lis(void)
{
    int i, j, maxi;
    int out[MAXN];
    /* init */
    for (i = 0; i < n; i++) {
        len[i] = 1;
        pre[i] = -1;
    }

    for (i = 0; i < n; i++)
        for (j = i + 1; j < n; j++)
            if (seq[j] > seq[i] && len[j] < len[i] + 1) {
                len[j] = len[i] + 1;
                pre[j] = i;
            }

    for (i = 1, maxi = 0; i < n; i++)
        if (len[i] > len[maxi])
            maxi = i;

    /* output */
    printf("Max hits: %d\n", len[maxi]);
    i = 0;
    while (1) {
        out[i++] = seq[maxi];
        if (pre[maxi] == -1)
            break;
        maxi = pre[maxi];
    }
    for (j = i - 1; j > -1; j--)
        printf("%d\n", out[j]);
}

ACM 481 What Goes Up

Longest Increasing Subsequence問題。
用正常的O(n ^ 2)的演算法去解竟然會TL,傻眼……
結果只好開始看別人是怎麼AC的。
結果AC一定要用O(nlogn)的演算法……
就開始看……我發現我看不懂 ToT。

反正就是找了一堆資料,然後寫法都很數學式,又是英文,
而且又沒範例 = =,只能說GG啊。

最後還是在這裡
找到範例碼,真是揪甘心~

重點就是要了解Patience sorting的運作原理即可。
Patience sorting大概是這樣:
1.如果沒有pile,就做一個pile。
2.每次把x值與pile最上的值相比,若x值 < pile的top值,
就把x放到該pile上。
若無,就再做一個pile。
3.反覆,到沒有x值為此。

這樣講可能很複雜,直接舉實例說明:
-7 10 9 2 3 8 8 1。
一開始是-7,沒pile,所以給-7一個pile:
-7,
接著是10,10 > -7,所以make a new pile:
-7
10,
再來是9, 9 > -7,所以不能放在pile1,
但9 < 10,所以放在pile2上,
-7
10 9,
反覆此動作我們最後可以得到:
-7
10 9 2 1
3
8
(因為Patience sorting是針對撲克牌做sort,
所以有重複的數字,我們就不再處理第二次)
如此,我們得到4個pile。
也就是lis為4。
第1到第4個位置分別可以放-7、10 9 2 1、3、8。
注意,上面這個例子並不表示,所有lis為4的組合……
也就是每個數字其實是獨立的,不能放在一起看,
除非我們找到一組順序,使得此子序列的對應關係合於本來的序列。
好吧,其實我不是很懂Patience sorting……
總之pile數 = lis數就對了!
那這樣要怎麼找到一組lis呢?
現在我們已經知道,每個位置能放的值了,
所以按照題目要求,我們只要從最末的值開始往前找即可。
這部份就跟O(n ^ 2)的方法是一樣的。

接著談實作,實作非常之令我苦惱……
所謂懂還不一定寫得出程式碼,就是這回事,囧。
首先要做出一個pile,所以讓seq[0]為第一個pile,
然後我們可以發現,Patience sorting其實是一個遞增數列(這應該是重點)。
也就是說,每個pile最上面的值,排在一起,一定為遞增數列。
既然是遞增,那我們可以用binary search去做search的動作。
(因為已經sort,所以可以用bin search)
兩種情況:
(1)seq[x]的值,比最後一個pile 的top值還大,就增加一個pile。
因為我們已知所有pile的top為一遞增數列,
那如果seq[x] > 最後一個pile的top值,
勢必seq[x],大於所有pile的tope值,
所以這時候就要增加一個pile。
(2)非(1)的情況,表示seq[x] <= 最後一個pile的top值。
這時候,seq[x]這個值,可能跟前面某個pile的top值一樣,
或是介於某兩個pile值之間的情況。
如果是前者,那我們找到seq[x] == pile top時,任務就結束了。
如果是後者,那我們會得到pile[i] top < seq[x] < pile[i + 1] top。
這時,需把pile[i + 1]的top換成seq[x]才行。
如此才符合Patience sorting的第二個定義。

所以我們可以得到一種資料結構:stack包含stack,
但是實作上不用這麼麻煩,只要用stack + 取代就好了。
其實更好的作法是再用一個空間,去紀錄每個seq[x]的在lis位置,
就是紀錄他在哪個pile啦!用空間換取時間!

這樣,我們已經知道了pile數(lis長度),
也紀錄了每個seq[x]所在lis長度的位置,
那麼這題就有解了!
從最後一個seq[x]往前到seq[0],去尋找符合lis長度的值,
找到該值後記錄下來,再把lis長度 - 1,同樣做找值的動作,
一直找到第一個lis為止。
如此,就是答案了。

另外為什麼是O(n * log(n))呢,
因為binary search是O(log(n)),
而有n個值,最慘的情況就是每個值都去做binary search,
那就會得到O(n * log(n))。

再一次感謝DJWS~
有興趣可以再看一些參考資料
wiki跟algorithmist都有。

/* ACM 481 What Goes Up
 * mythnc
 * 2012/01/16 09:58:36   
 * run time: 0.044
 */
#include <stdio.h>

#define MAXN 100000

void lis(int);
void binsearch(int, int, int);

int n;
int seq[MAXN], pos[MAXN], v[MAXN];

int main(void)
{

    n = 0;
    while (scanf("%d", &seq[n]) == 1)
        n++;

    lis(n);

    return 0;
}

/* lis: return the last max len position */
void lis(int n)
{
    int len, i, j;
    int out[MAXN];

    len = 0;
    v[len++] = seq[0];
    pos[0] = 0;

    for (i = 1; i < n; i++) {
        if (seq[i] > v[len - 1]) {
            v[len] = seq[i];
            pos[i] = len++;
        }
        else
            binsearch(0, len, i);
    }
    /* output */
    printf("%d\n-\n", len);
    for (i = n - 1, j = len - 1; i > -1 && j > -1; i--)
        if (pos[i] == j) {
            out[j] = seq[i];
            j--;
        }
    for (i = 0; i < len; i++)
        printf("%d\n", out[i]);
}

void binsearch(int begin, int end, int index)
{
    int mid;

    while (begin <= end) {
        mid = (begin + end) / 2;
        if (v[mid] == seq[index]) {
            pos[index] = mid;
            return;
        }
        else if (v[mid] > seq[index])
            end = mid - 1;
        else
            begin = mid + 1;
    }
    
    mid = (begin + end) / 2;
    if (mid == 0 && index == 1) {
        v[0] = seq[index];
        pos[index] = 0;
    }
    else {
        v[mid + 1] = seq[index];
        pos[index] = mid + 1;
    }
}

20120115

ACM 231 Testing the CATCHER

Longest Increasing Subsequence反過來做!
變成Longest Decreasing Subsequence!

/* ACM 231 Testing the CATCHER
 * mythnc
 * 2012/01/15 21:19:58   
 * run time: 0.004
 */
#include <stdio.h>

int input(int *);
int lds(int *, int);

#define MAXM 10000

int main(void)
{
    int set, data;
    int catcher[MAXM];

    set = 0;
    while (scanf("%d", &data) && data != -1) {
        catcher[0] = data;
        if (set > 0)
            putchar('\n');
        printf("Test #%d:\n", ++set);
        printf("  maximum possible interceptions: %d\n",
               lds(catcher, input(catcher)));
    }

    return 0;
}

/* input: receive input data
 * and return the number of missile */
int input(int *catcher)
{
    int i;

    i = 1;
    while (scanf("%d", &catcher[i]) && catcher[i] != -1)
        i++;

    return i;
}

/* lds: return the longest decrement subsequence length */
int lds(int *catcher, int n)
{
    int len[MAXM];
    int i, j, maxlen;

    for (i = 0; i < n; i++)
        len[i] = 1;

    for (i = 0; i < n; i++)
        for (j = i + 1; j < n; j++)
            if (catcher[j] < catcher[i] && len[j] < len[i] + 1)
                len[j] = len[i] + 1;
                
    for (i = maxlen = 0; i < n; i++)
        if (len[i] > maxlen)
            maxlen = len[i];

    return maxlen;
}

ACM 103 Stacking Boxes

其實是一個Longest Increasing Subsequence……
相關的教學可以看這裡
之前想說應該是做3個sort,
先對維度做sort,接著對每個維度的第一個維度sort,
接著把所有的box依照sort就有解。
後來想想好像不對……

所以第三步驟其實不是作sort,是做LIS。
把整個題目想成是一個box lis就很簡單了。
單一個box由n個維度構成,所以box的大小由n個維度所決定。
而維度內先排列是必要的(因為要跟其他box比大小)
而題目要作最多的「大包小」的動作。
所以先把每個box依照大小順序做排列也是必要的。
如此小的在前面,大的在後面,才可以找出最多的「大包小」。

/* ACM 103 Stacking Boxes
 * mythnc
 * 2012/01/15 14:42:45   
 * run time: 0.008
 */
#include <stdio.h>
#include <stdlib.h>

#define MAXBOX 30
#define MAXD   10

typedef struct box {
    int num;
    int dimen[MAXD];
} Box;

void init(int, int);
int cmpd(const void *, const void *);
int cmpb(const void *, const void *);
int lis(int, int);
void output(int);

Box b[MAXBOX];
int len[MAXBOX], pre[MAXBOX];

int main(void)
{
    int n, d;

    while (scanf("%d %d", &n, &d) == 2) {
        init(n, d);
        output(lis(n, d));
    }

    return 0;
}

/* init: receive input data, initialize b content,
 * and sort data */
void init(int n, int d)
{
    int i, j;

    for (i = 0; i < n; i++) {
        b[i].num = i + 1;
        len[i] = 1;
        pre[i] = -1;
        for (j = 0; j < d; j++)
            scanf("%d", &b[i].dimen[j]);
        qsort(b[i].dimen, d, sizeof(int), cmpd);
    }
    qsort(b, n, sizeof(Box), cmpb);
}

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

/* cmpb: sort dimen[0] for qsort() */
int cmpb(const void *a, const void *b)
{
    return ((Box *)a)->dimen[0] - ((Box *)b)->dimen[0];
}

/* lis: find longest increasing subsequence.
 * the unit is "box"
 * return its pos */
int lis(int n, int d)
{
    int i, j, k, maxi;

    for (i = 0; i < n; i++)
        for (j = i + 1; j < n; j++) {
            for (k = 0; k < d && b[j].dimen[k] > b[i].dimen[k]; k++)
                ;
            if (k == d && len[i] + 1 > len[j]) {
                len[j] = len[i] + 1;
                pre[j] = i;
            }
        }

    for (i = 1, maxi = 0; i < n; i++)
        if (len[i] > len[maxi])
            maxi = i;

    return maxi;
}

/* output: output lis len and seq */
void output(int i)
{
    int num;
    int inc[MAXBOX];
    /* output max lis len */
    printf("%d\n", len[i]);

    num = 0;
    while (1) {
        inc[num++] = b[i].num;
        if (pre[i] == -1)
            break;
        i = pre[i];
    }
    /* out lis seq */
    printf("%d", inc[--num]);
    for (i = num - 1; i > -1; i--)
        printf(" %d", inc[i]);
    putchar('\n');
}

20120114

ACM 10608 Friends

Union-Find Disjoint Sets。
ACM10583
這次用weightedunion + collapsingfind去解。

原本直接把第一行吃掉不處理,
結果一直WA……
後來吃掉第一行並做處理後就AC了 =.=。
這測資有問題……可能是m後面不只m行……
心機啊!

/* ACM 10608 Friends
 * mythnc
 * 2012/01/14 23:12:34   
 * run time: 0.076
 */
#include <stdio.h>

#define MAXNODE 30001

void init(int);
void input(int);
int collapsingfind(int);
void weightedunion(int, int);
int count(int);

int node[MAXNODE];

int main(void)
{
    int n, m, set;

    scanf("%d", &set);
    while(set--) {
        scanf("%d %d", &n, &m);
        init(n);
        input(m);
        printf("%d\n", count(n));
    }

    return 0;
}

/* init: initialize each node to different sets */
void init(int n)
{
    int i;

    for (i = 1; i <= n; i++)
        node[i] = -1;
}

void input(int n)
{
    int i, v1, v2;

    for (i = 0; i < n; i++) {
        scanf("%d %d", &v1, &v2);
        weightedunion(collapsingfind(v1), collapsingfind(v2));
    }
}

/* collapsingfind: find root first,
 * then use collapsing rule to collapse all nodes
 * form v to root. return the set of node v */
int collapsingfind(int v)
{
    int root, trail, tmp;

    for (root = v; node[root] >= 0; root = node[root])
        ;
    for (trail = v; trail != root; trail = node[trail]) {
        tmp = trail;
        node[tmp] = root;
    }

    return root;
}

/* weightedunoin: union s1 and s2 */
void weightedunion(int s1, int s2)
{
    if (s1 == s2)
        return;

    if (s1 <= s2) {
        node[s1] += node[s2];
        node[s2] = s1;
    }
    else {
        node[s2] += node[s1];
        node[s1] = s2;
    }
}

/* count: return the max nodes set */
int count(int n)
{
    int min, i;

    for (i = 1, min = -1; i <= n; i++)
        if (node[i] < min)
            min = node[i];

    return -min;
}

ACM 10583 Ubiquitous Religions

Union-Find Disjoint Sets。
還是一樣做weighted union。

/* ACM 10583 Ubiquitous Religions
 * mythnc
 * 2012/01/14 22:48:07   
 * run time: 0.2
 */
#include <stdio.h>

#define MAXNODE 50001

void init(int);
void input(int);
int find(int);
void weightedunion(int, int);
void output(int *, int);
int count(int);

int node[MAXNODE];

int main(void)
{
    int n, m, set;

    set = 0;
    while (scanf("%d %d", &n, &m) && n != 0) {
        init(n);
        input(m);
        output(&set, n);
    }

    return 0;
}

/* init: initialize each node to different sets */
void init(int n)
{
    int i;

    for (i = 1; i <= n; i++)
        node[i] = -1;
}

void input(int n)
{
    int i, v1, v2;

    for (i = 0; i < n; i++) {
        scanf("%d %d", &v1, &v2);
        weightedunion(find(v1), find(v2));
    }
}

/* find: return the set of node v */
int find(int v)
{
    for (; node[v] >= 0; v = node[v])
        ;

    return v;
}

/* weightedunoin: union s1 and s2 */
void weightedunion(int s1, int s2)
{
    if (s1 == s2)
        return;

    if (s1 <= s2) {
        node[s1] += node[s2];
        node[s2] = s1;
    }
    else {
        node[s2] += node[s1];
        node[s1] = s2;
    }
}

/* output: output result */
void output(int *set, int n)
{
    printf("Case %d: %d\n", ++*set, count(n));
}

/* count: return the number of different sets */
int count(int n)
{
    int sum, i;

    for (i = 1, sum = 0; i <= n; i++)
        if (node[i] < 0)
            sum++;

    return sum;
}

ACM 793 Network Connections

一樣是Union-Find Disjoint Sets。
這次用weightedunion實作。

/* ACM 793 Network Connections
 * mythnc
 * 2012/01/14 12:41:37   
 * run time: 0.072
 */
#include <stdio.h>

#define MAXNODE 10001
#define LINEMAX 100

typedef enum {FALSE = 0, TRUE} bool;

void init(int *, int);
int find(int, int *);
void weightedunion(int, int, int *);

int main(void)
{
    int node[MAXNODE];
    bool set;
    int n, v1, v2, yes, no;
    char line[LINEMAX];

    scanf("%*d");
    getchar(); /* eat '\n' */
    getchar(); /* eat blank line */
    set = FALSE;
    while (fgets(line, LINEMAX, stdin))
        switch (line[0]) {
            /* compare */
            case 'q':
                sscanf(line, "%*c %d %d", &v1, &v2);
                if (find(v1, node) == find(v2, node))
                    yes++;
                else
                    no++;
                break;
            /* add */
            case 'c':
                sscanf(line, "%*c %d %d", &v1, &v2);
                weightedunion(find(v1, node), find(v2, node), node);
                break;
            /* output */
            case '\n':
                if (set)
                    putchar('\n');
                printf("%d,%d\n", yes, no);
                set = TRUE;
                break;
            default:
                sscanf(line, "%d", &n);
                init(node, n);
                yes = no = 0;
        }
    /* output last data set */
    if (set)
        putchar('\n');
    printf("%d,%d\n", yes, no);

    return 0;
}

/* init: init each node to disjoint set */
void init(int *node, int n)
{
    int i;

    for (i = 1; i <= n; i++)
        node[i] = -1;
}

/* find: find the set of node v */
int find(int v, int *node)
{
    for (; node[v] >= 0; v = node[v])
        ;

    return v;
}

/* weightedunoin: do i and j set union to one set */
void weightedunion(int i, int j, int *node)
{
    if (i == j)
        return;

    if (i <= j) {
        node[i] += node[j];
        node[j] = i;
    }
    else {
        node[j] += node[i];
        node[i] = j;
    }
}

ACM 459 Graph Connectivity

Union-Find Disjoint Sets標準題!

char轉int並做map,
接著find set再做union即可

/* ACM 459 Graph Connectivity
 * mythnc
 * 2012/01/13 23:34:04   
 * run time: 0.020
 */
#include <stdio.h>

#define MAXLETTER 26
#define LINEMAX   4  /* 2 + '\n' + '\0' */

void init(int *, int);
int find(int *, int);
void unionsub(int, int, int *);
int count(int *, int);

int main(void)
{
    int i, set, n;
    int node[MAXLETTER];
    char c;
    char token[LINEMAX];

    scanf("%d", &set);
    getchar(); /* eat '\n' */
    scanf("%*c"); /* eat blank line */
    for (i = 0; i < set; i++) {
        scanf("%c", &c);
        getchar();
        n = c - 'A' + 1;
        init(node, n);
        while (fgets(token, LINEMAX, stdin) && token[0] != '\n')
            unionsub(find(node, token[0] - 'A'), find(node, token[1] - 'A'), node);
        /* ouput */
        if (i > 0)
            putchar('\n');
        printf("%d\n", count(node, n));
    }

    return 0;
}

/* init: initialize each node to -1 */
void init(int *node, int n)
{
    int i;

    for (i = 0; i < n; i++)
        node[i] = -1;
}

/* find: find root of node x */
int find(int *node, int x)
{
    for (; node[x] != -1; x = node[x])
        ;
    return x;
}

/* unionsub: union i and j two sets to one set */
void unionsub(int i, int j, int *node)
{
    if (i != j)
        node[i] = j;
}

/* count: return the number of subgraph */
int count(int *node, int n)
{
    int sum, i;

    for (i = sum = 0; i < n; i++)
        if (node[i] < 0)
            sum++;

    return sum;
}

20120113

ACM 291 The House Of Santa Claus

一筆劃問題。
相對於以點(vertex)為準的dfs,做以線(edge)為準的dfs即可。

不過問題就來了,如何表示edge是否走訪呢?
我的作法是做一個visited[MAXEDGE],
接著在graph的struct中增加一筆pos資料,
表示edge所在visited的位置。
從vertex 1開始走訪,
每次都判斷是否還有edge可以走訪,
若有就繼續走,走到edge == 9即可。
(共8個點,所以走到第九次就要output)

話說關於graph的問題我都用adjancency list去做,
從來沒用過adjancency martix,在這裡
看到人家用adjancency martix的解法……真是為之驚嘆!
看來我殺雞用牛刀,開太空梭買菜了 -_-。

所以其實也可以做以點為準的dfs,
但是要紀錄的是edge,走訪到第九層就做output + return即可。
用一個二維陣列做graph,另一個二維陣列做edge紀錄!
偉哉adjancency martix!

所以重點其實是紀錄點或是紀錄線嘛……

/* ACM 291 The House Of Santa Claus
 * mythnc
 * 2012/01/13 18:53:08   
 * run time: 0.004
 */
#include <stdio.h>
#include <stdlib.h>

#define MAXEDGE 8
#define MAXNODE 6 /* Node 0~5 */

typedef struct node {
    /* pos: edge position */
    int pos, node;
    struct node *next;
} Node;

typedef enum {FALSE = 0, TRUE} bool;

void init(int, int, int);
void backtrack(int, int);
void freeg(void);

Node *g[MAXNODE] = {NULL};
/* record edge is visited or not */
bool visited[MAXEDGE];
char output[MAXEDGE + 1];

int main(void)
{
    int i;

    init(1, 2, 0);
    init(2, 1, 0);
    init(1, 3, 1);
    init(3, 1, 1);
    init(1, 5, 2);
    init(5, 1, 2);
    init(2, 3, 3);
    init(3, 2, 3);
    init(2, 5, 4);
    init(5, 2, 4);
    init(3, 4, 5);
    init(4, 3, 5);
    init(3, 5, 6);
    init(5, 3, 6);
    init(4, 5, 7);
    init(5, 4, 7);

    output[0] = 1 + '0';
    backtrack(1, 1);
    freeg();

    return 0;
}

/* init: initialize graph */
void init(int v1, int v2, int pos)
{
    Node *pt, *tmp;

    tmp = (Node *)malloc(sizeof(Node));
    tmp->next = NULL;
    tmp->node = v2;
    tmp->pos = pos;

    if (g[v1] == NULL) {
        g[v1] = tmp;
        return;
    }
    pt = g[v1];
    while (pt->next != NULL)
        pt = pt->next;
    pt->next = tmp;
}

/* backtrack: use backtracking method to output answer */
void backtrack(int index, int node)
{
    Node *pt;
    int pos;

    if (index == MAXEDGE + 1) {
        output[index] = '\0';
        printf("%s\n", output);
        return;
    }

    for (pt = g[node]; pt; pt = pt->next) {
        pos = pt->pos;
        node = pt->node;
        if (!visited[pos]) {
            visited[pos] = TRUE;
            output[index] = node + '0';
            backtrack(index + 1, node);
            visited[pos] = FALSE;
        }
    }
}

/* freeg: free all graph node */
void freeg(void)
{
    Node *pt, *tmp;
    int i;

    for (i = 0; i < MAXNODE; i++) {
        pt = g[i];
        while (pt != NULL) {
            tmp = pt;
            pt = pt->next;
            free(tmp);
        }
    }
}

ACM 336 A Node Too Far

BFS或DFS。 話說用BFS沒有實際想像的好……
走訪次數還要另外紀錄
所以用DFS應該也無不可吧?
不知道有沒有更好的方法?

第一次莫名其妙的RE。
也不知道是哪裡有問題……
只好防呆一下。
(1)假設input給的兩點為同一點 -> edge to self node。
這時候不做update(),只做addg()。
(2)假設給的node跟ttl,其中node不為graph上的任一點,當然未走訪任一點。
所以不做走訪,直接回傳node數。
防呆之後,再上傳一次就莫名其妙AC了。
可能(1)跟(2)都要防呆一下就ok。

第一次用union,不知效果如何。
其實都是int,但是意義不太一樣。
一個是pointer of array的node,一個是array連出去的linked list node。
在array的field表示該數字,
linked list上的field表示該數字所在的位置。
原本想在linked list上也存該數字,
但是數字又要轉成位置,
所以就直接存位置,省去一次轉換。

/* ACM 336 A Node Too Far
 * mythnc
 * 2012/01/13 13:10:30   
 * run time: 0.052
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAXNODE 30

/* save num in array node, but save pos in linked node */
typedef union name {
    int num, pos;
} u;

typedef struct node {
    u field;
    /* times: the ttl times */
    int times;
    struct node *next;
} Node;

typedef enum {FALSE = 0, TRUE} bool;

void input(int);
int search(int);
int addg(int);
void update(int, int);
int bfs(int, int);
void addq(int);
int deleteq(void);
void freeg(void);

Node graph[MAXNODE];
int numnode, front, end;
int queue[MAXNODE];
bool visited[MAXNODE];

int main(void)
{
    int edge, v, ttl, set, sum;

    set = 0;
    while (scanf("%d", &edge) && edge != 0) {
        input(edge);
        while (scanf("%d %d", &v, &ttl) && !(v == 0 && ttl == 0)) {
            sum = bfs(search(v), ttl);
            printf("Case %d: %d nodes not reachable from node %d with TTL = %d.\n",
                   ++set, sum, v, ttl);
        }
        freeg();
    }

    return 0;
}

/* input: receive edge and initialize graph */
void input(int n)
{
    int i, v1, v2, pos1, pos2;

    for (i = numnode = 0; i < n; i++) {
        scanf("%d %d", &v1, &v2);
        pos1 = search(v1);
        if (pos1 == -1)
            pos1 = addg(v1);
        pos2 = search(v2);
        if (pos2 == -1)
            pos2 = addg(v2);
        if (pos1 != pos2) {
            update(pos1, pos2);
            update(pos2, pos1);
        }
    }
}

/* search: find v in graph.
 * if find return its position
 * else return -1 */
int search(int v)
{
    int i;

    for (i = 0; i < numnode; i++)
        if (graph[i].field.num == v)     
            return i;

    return -1;
}

/* addg: add v in graph and
 * return the postion of v */
int addg(int v)
{
    graph[numnode].field.num = v;
    graph[numnode].next = NULL;

    return numnode++;
}

/* update: update the edges of pos1 and pos2 */
void update(int pos1, int pos2)
{
    Node *pt, *tmp;

    tmp = (Node *)malloc(sizeof(Node));
    tmp->field.pos = pos2;
    tmp->next = NULL;

    pt = graph[pos1].next;
    if (pt == NULL) {
        graph[pos1].next = tmp;
        return;
    }
    /* find last link node */
    while (pt->next != NULL)
        pt = pt->next;
    pt->next = tmp;
}

/* bfs: do bfs. the times of bfs has to equal to ttl
 * return unvisited node number */
int bfs(int pos, int ttl)
{
    int times, sum;
    Node *pt;
    sum = numnode;
    /* no such node */
    if (pos == -1)
        return sum;
    /* init visited array, queue tag and graph[pos] times */
    memset(visited, FALSE, MAXNODE * sizeof(int));
    front = end = graph[pos].times = 0;

    visited[pos] = TRUE;
    sum--;
    if (graph[pos].times == ttl)
        return sum;

    addq(pos);
    while (front != end) {
        pos = deleteq();
        for (times = graph[pos].times + 1, pt = graph[pos].next; pt; pt = pt->next) {
            pos = pt->field.pos;
            if (!visited[pos]) {
                visited[pos] = TRUE;
                sum--;
                graph[pos].times = times;
                if (times < ttl)
                    addq(pos);
            }
        }
    }

    return sum;
}

/* addq: add the graph[pos] and its adjacency node
 * to queue */
void addq(int pos)
{
    queue[end++] = pos;
    end %= MAXNODE;
}

/* deleteq: delete the 1st element in queue.
 * and return the element */
int deleteq(void)
{
    int pos;

    pos = queue[front++];
    front %= MAXNODE;

    return pos;
}

/* freeg: free graph node */
void freeg(void)
{
    Node *pt, *tmp;
    int i;

    for (i = 0; i < numnode; i++) {
        pt = graph[i].next;
        while (pt != NULL) {
            tmp = pt;
            pt = pt->next;
            free(tmp);
        }
    }
}

ACM 727 Equation

infix轉postfix。

讓我想到當年的作業了……
雖然當時要寫判斷合法、中序轉後續跟算值。
不過括號問題還傻傻的暴力解,兩個禮拜才把東西生出來,真是寫到快起肖。
用stack不就輕鬆多了嗎 -.-

結果現在1hr就完成中序轉後序,囧。

operand直接output,
operator要判斷優先度。
當吃進來的operator優先度比stack[top]優先度高,
就直接push;
低或相等的話,pop到stack[top]比operator高或stack為空為止。
所以(最高,直接丟到stack。
/、*次高,若top是*、/就要先pop,再push。
+、-最低,遇到其他+、-、*、/都要pop,再push。
遇到)要無條件pop到(為止。

(算是特例,吃進來時最高,但是在top時最低。
所以+、-、*、/遇到top為(時,就可以直接push。

最後當吃進來的token為'\0'時,pop到stack為空為止即可。
最後就是output格式問題。

/* ACM 727 Equation
 * mythnc
 * 2012/01/13 09:44:34
 * run time: 0.136
 */
#include <stdio.h>
#include <string.h>

#define LINEMAX  10
#define MAXSTACK 50

void postfix(void);
void pop(void);
void push(char *);

char stack[LINEMAX][MAXSTACK];
int count;

int main(void)
{
    scanf("%*d");
    getchar();
    getchar();
    postfix();

    return 0;
}

/* postfix: infix to postfix */
void postfix(void)
{
    char line[LINEMAX];

    count = 0;
    while (fgets(line, LINEMAX, stdin)) {
        line[strlen(line) - 1] = '\0';
        /* operator */
        if (line[0] == '+' || line[0] == '-' && strlen(line) == 1) {
            while (count > 0 && stack[count - 1][0] != '(')
                pop();
            push(line);
        }
        else if (line[0] == '*' || line[0] == '/') {
            while (count > 0 && stack[count - 1][0] != '('
                   && stack[count - 1][0] != '+' && stack[count - 1][0] != '-')
                pop();
            push(line);
        }
        else if (line[0] == '(')
            push(line);
        else if (line[0] == ')') {
            while (stack[count - 1][0] != '(')
                pop();
            count--;
        }
        /* terminal condition */
        else if (line[0] == '\0') {
            while (count != 0)
                pop();
            printf("\n\n");
        }
        /* operand */
        else
            printf("%s", line);
    }
    while (count != 0)
        pop();
    putchar('\n');
}

/* pop: print out the top element */
void pop(void)
{
    printf("%s", stack[--count]);
}

/* push: push line to stack */
void push(char *line)
{
    strcpy(stack[count++], line);
}

20120112

ACM 514 Rails

又是一題腦殘題……
題目給的output最後的Yes下面空行,
但是要我們上傳的output最後要有空行。
=.=,真是有夠機車。

用stack就可以解,其實不用stack也可以解,懶得想了……
被stupid output搞得好煩……

/* ACM 514 Rails
 * mythnc
 * 2012/01/12 21:22:57   
 * run time: 0.076
 */
#include <stdio.h>

#define MAX 1000

typedef enum {FALSE = 0, TRUE} bool;

void init(int *, int);
bool input(int *, int);
bool simulate(int *, int *, int);
void push(int);
int pop(void);
int top(void);

int stack[MAX];
int count;

int main(void)
{
    int n;
    int list[MAX], cmp[MAX];

    while (scanf("%d", &n) && n != 0) {
        init(list, n);
        while (input(cmp, n))
            if (simulate(list, cmp, n))
                printf("Yes\n");
            else
                printf("No\n");
        putchar('\n');
    }

    return 0;
}

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

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

/* input: receive input data */
bool input(int *cmp, int n)
{
    int i;

    for (i = 0; i < n; i++) {
        scanf("%d", &cmp[i]);
        if (cmp[i] == 0)
            return FALSE;
    }

    return TRUE;
}

/* simulate: simulate coaches state */
bool simulate(int *list, int *cmp, int n)
{
    int i, j;
    
    for (i = j = count = 0; i < n; i++) {
        if (j < n && list[j] == cmp[i])
            j++;
        else if (count != 0 && top() == cmp[i])
            pop();
        else if (j < n && list[j] != cmp[i]) {
            while (j < n && cmp[i] != list[j])
                push(list[j++]);
            if (j == n || list[j] != cmp[i])
                return FALSE;
            j++;
        }
        else
            return FALSE;
    }

    return TRUE;
}

/* push: push x in top */
void push(int x)
{
    stack[count++] = x;
}

/* pop: pop the top value */
int pop(void)
{
    return stack[--count];
}

/* top: return top value */
int top(void)
{
    return stack[count - 1];
}

ACM 127 "Accordian" Patience

stack。
其實可以使用在單一空間上表示多個stack的方式,
不過這樣要移來移去,好累啊……
都給每個pile一個stack不就很方便嗎!

pile用linked list實作,
(本來想用array,但是每次empty就要copy,超麻煩)
每個pile各有一個stack。
從第一個pile到最後一個pile。
每次都先-3,再-1。
每次減完要判斷是否在pile中,
若在pile中要檢查是否match,
若match,就做pop跟push。
pop完要判斷該pile是否empty,
若empty就移出linked list。
之後移到push的pile上繼續做-3、-1的動作。
若-3與-1皆沒match,那就移到下一個pile繼續-3、-1。

一次就AC,超爽的~

/* ACM 127 "Accordian" Patience
 * mythnc
 * 2012/01/12 17:02:02   
 * run time: 0.296
 */
#include <stdio.h>
#include <string.h>

#define MAX     52
#define MAXCHAR 3

typedef struct pile {
    char card[MAX][MAXCHAR];
    int count;
    struct pile *next, *pre;
} Pile;

typedef enum {FALSE = 0, TRUE} bool;

void input(Pile *);
int simulate(Pile *);
bool match(Pile *, Pile *);
void push(Pile *, char *);
void pop(Pile *, char *);
bool empty(Pile *);
void relink(Pile *);
void output(Pile *, int);

int main(void)
{
    Pile p[MAX];
    int n;

    while (scanf("%s", p[0].card[0]) && p[0].card[0][0] != '#') {
        input(p);
        n = simulate(p);
        output(p, n);
    }

    return 0;
}

/* input: receive input data and initialize */
void input(Pile *p)
{
    int i;

    p[0].count = 1;
    p[0].pre = NULL;
    p[0].next = &p[1];
    for (i = 1; i < MAX; i++) {
        scanf("%s", p[i].card[0]);
        p[i].count = 1;
        p[i].pre = &p[i - 1];
        if (i != MAX - 1)
            p[i].next = &p[i + 1];
        else
            p[i].next = NULL;
    }
}

/* simulate: simulate Accordian */
int simulate(Pile *head)
{
    int n, i;
    Pile *pt, *cmp;
    char s[MAXCHAR];

    n = MAX;
    for (pt = head; pt;) {
        /* 3rd pile to the left */
        for (i = 1, cmp = pt->pre; cmp && i < 3; cmp = cmp->pre, i++)
            ;
        if (cmp && match(pt, cmp)) {
            pop(pt, s);
            push(cmp, s);
            if (empty(pt)) {
                relink(pt);
                n--;
            }
            pt = cmp;
            continue;
        }
        /* neighbour on the left */
        cmp = pt->pre;
        if (cmp && match(pt, cmp)) {
            pop(pt, s);
            push(cmp, s);
            if (empty(pt)) {
                relink(pt);
                n--;
            }
            pt = cmp;
            continue;
        }
        pt = pt->next;
    }

    return n;
}

/* match: match condition */
bool match(Pile *p, Pile *q)
{
    return q->card[q->count - 1][0] == p->card[p->count - 1][0]
        || q->card[q->count - 1][1] == p->card[p->count - 1][1];
}

/* push: put s in top of p */
void push(Pile *p, char *s)
{
    strcpy(p->card[p->count++], s);
}

/* pop: pop out the top card */
void pop(Pile *p, char *s)
{
    strcpy(s, p->card[--p->count]);
}

/* empty: return TRUE if stack is empty
 * else return FALSE */
bool empty(Pile *p)
{
    return p->count == 0;
}

/* relink: rearrange linked list */
void relink(Pile *p)
{
    if (p->pre)
        p->pre->next = p->next;
    if (p->next)
        p->next->pre = p->pre;
}

/* output: output result */
void output(Pile *p, int n)
{
    if (n == 1) {
        printf("1 pile remaining: 52\n");
        return;
    }

    printf("%d piles remaining:", n);
    for (; p; p = p->next)
        printf(" %d", p->count);
    putchar('\n');
}

ACM 11462 Age Sort

sort it!

/* ACM 11462 Age Sort
 * mythnc
 * 2012/01/12 11:17:32   
 * run time: 0.856
 */
#include <stdio.h>
#include <stdlib.h>

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

int main(void)
{
    int n;
    int *list;

    while (scanf("%d", &n) && n != 0) {
        list = (int *)malloc(sizeof(int) * n);
        input(list, n);
        qsort(list, n, sizeof(int), cmp);
        output(list, n);
        free(list);
    }
    return 0;
}

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

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

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

/* output: output result */
void output(int *list, int n)
{
    int i;

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

ACM 10810 Ultra-QuickSort

ACM10327
做stable sort,計算swap次數。
最大次數為maxn * (maxn - 1) / 2。
所以用long long。

/* ACM 10810 Ultra-QuickSort
 * mythnc
 * 2012/01/12 10:43:46   
 * run time: 0.196
 */
#include <stdio.h>
#include <stdlib.h>

void input(int *, int);
long long merge(int *, int *, int, int);

int main(void)
{
    int n;
    int *ary, *tmp;

    while (scanf("%d", &n) && n != 0) {
        ary = (int *)malloc(sizeof(int) * n);
        tmp = (int *)malloc(sizeof(int) * n);
        input(ary, n);
        printf("%lld\n", merge(ary, tmp, 0, n));
        free(ary);
        free(tmp);
    }

    return 0;
}

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

    for (i = 0; i < n; i++)
        scanf("%d", &ary[i]);
}

/* merge: merge sort */
long long merge(int *ary, int *tmp, int head, int tail)
{
    int half, i, j, k;
    long long c;

    /* already sorted */
    if (tail - head == 1)
        return 0;
    /* unsorted list -> merge into 2 sub lists */
    half = (head + tail) / 2;  /* (x / 2) == (x >> 1) */
    c = merge(ary, tmp, head, half);
    c += merge(ary, tmp, half, tail);
    /* sort 2 sublists and merge */
    k = i = head;
    j = half;
    while (i < half && j < tail)
        if (ary[j] < ary[i]) {
            tmp[k++] = ary[j++];
            c += half - i;
        }
        else
            tmp[k++] = ary[i++];
    while (i < half)
        tmp[k++] = ary[i++];
    while (j < tail)
        tmp[k++] = ary[j++];
    for (i = head; i < tail; i++)  /* copy the sorted list to ary */
        ary[i] = tmp[i];

    return c;
}

ACM 10258 Contest Scoreboard

又一題腦殘題……
每次寫到腦殘題頭都痛死惹……
首先problem數最多是13,不是什麼9……-.-。

另外只要得到correct之後,
不管之後又得到correct或是incorrect,
通通不用管它……

問題是題目有寫嗎?有嗎?沒吧!
那誰知道這種機車狀況要怎麼處理?
定義一下會死嗎?
無聊!

/* ACM 10258 Contest Scoreboard
 * mythnc
 * 2012/01/11 23:07:41   
 * run time: 0.004
 */
#include <stdio.h>
#include <string.h>

#define LINEMAX 25
#define MAXP 13
#define MAXC 100

typedef struct contestant {
    int num, solved, penalty;
    int tried[MAXP], ac[MAXP];
} Contestant;

typedef enum {FALSE = 0, TRUE} bool;

int input(Contestant *);
int find(Contestant *, int, int);
int cmp(const void *, const void *);
void output(Contestant *, int);

int main(void)
{
    Contestant con[MAXC];
    int set, i, n;

    scanf("%d", &set);
    getchar();
    getchar();
    for (i = 0; i < set; i++) {
        if (i > 0)
            putchar('\n');
        n = input(con);
        qsort(con, n, sizeof(Contestant), cmp);
        output(con, n);
    }

    return 0;
}

/* input: receive input datas */
int input(Contestant *con)
{
    int num, prob, time, n, pos;
    char sub;
    char line[LINEMAX];

    n = 0;
    while (fgets(line, LINEMAX, stdin)) {
        if (strlen(line) <= 1) /* blank line */
            break;
        sscanf(line, "%d %d %d %c", &num, &prob, &time, &sub);
        pos = find(con, num, n);
        if (pos == -1) {
            /* add and init */
            con[n].num = num;
            con[n].solved = con[n].penalty = 0;
            memset(con[n].tried, 0, MAXP);
            memset(con[n].ac, FALSE, MAXP);
            pos = n++;
        }
        if (sub == 'C' && !con[pos].ac[prob - 1]) {
            con[pos].solved++;
            con[pos].penalty += time + con[pos].tried[prob - 1];
            con[pos].ac[prob - 1] = TRUE;
        }
        else if (sub == 'I' && !con[pos].ac[prob - 1])
            con[pos].tried[prob - 1] += 20;
    }

    return n;
}

/* find: if num in con return it's position
 * else retrn -1 */
int find(Contestant *con, int num, int n)
{
    int i;

    for (i = 0; i < n; i++)
        if (con[i].num == num)
            return i;

    return -1;
}

/* cmp: for qsort() */
int cmp(const void *a, const void *b)
{
    if (((Contestant *)a)->solved != ((Contestant *)b)->solved)
        return ((Contestant *)b)->solved - ((Contestant *)a)->solved;
    else if (((Contestant *)a)->penalty != ((Contestant *)b)->penalty)
        return ((Contestant *)a)->penalty - ((Contestant *)b)->penalty;
    else
        return ((Contestant *)a)->num - ((Contestant *)b)->num;
}

/* output: output results */
void output(Contestant *con, int n)
{
    int i;

    for (i = 0; i < n; i++)
        printf("%d %d %d\n", con[i].num, con[i].solved, con[i].penalty);
}

20120111

ACM 10194 Football (aka Soccer)

多key求sort。
課本寫得radix sort根本沒屁用 = =。
實作上insertion sort或是qsort皆可用來多key求sort。
其他sort沒測,不知道行不行。

從第一個key開始,如果key的兩值相等,就不做sort,跳到下一個key做判斷,
當兩值不相等時,才做sort,反覆這個步驟即可。

gd沒設初始一直WA Orz。

/* ACM 10194 Football (aka Soccer)
 * mythnc
 * 2012/01/11 16:12:21   
 * run time: 0.008
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXRACEN 110
#define MAXTEAMN 40
#define MAXTEAM  30
#define SWAP(X, Y, T) (T = X, X = Y, Y = T)

typedef struct team {
    char name[MAXTEAMN];
    int pt, win, tie, lose;
    /* game played, goal diff, goal score, goal against */
    int gp, gd, gs, ga;
} Team;

int input(Team *, char *);
int findteam(char *, Team *, int);
void updateteam(Team *, int, int);
void output(Team *, int, char *);
void sort(Team *, int);

int main(void)
{
    int nrace, i;
    char racename[MAXRACEN];
    int nteam;
    Team t[MAXTEAM];

    scanf("%d", &nrace);
    getchar(); /* eat '\n' */
    for (i = 0; i < nrace; i++) {
        if (i > 0)
            putchar('\n');
        nteam = input(t, racename);
        sort(t, nteam);
        output(t, nteam, racename);
    }

    return 0;
}

/* input: receive input datas */
int input(Team *t, char *racename)
{
    int nteam, ngame, g1, g2, t1, t2;
    int i;
    char team1[MAXTEAMN], team2[MAXTEAMN];
    /* eat racename */
    fgets(racename, MAXRACEN, stdin);
    scanf("%d", &nteam);
    getchar(); /* eat '\n' */
    /* eat teamname */
    for (i = 0; i < nteam; i++) {
        scanf("%[^\n]\n", t[i].name);
        /* init */
        t[i].pt = t[i].win = t[i].tie = t[i].lose
        = t[i].gp = t[i].gd = t[i].gs = t[i].ga = 0;
    }
    scanf("%d", &ngame);
    getchar(); /* eat '\n' */
    /* eat game played */
    while (ngame--) {
        scanf("%[^#]#%d@%d#%[^\n]\n", team1, &g1, &g2, team2);
        t1 = findteam(team1, t, nteam);
        t2 = findteam(team2, t, nteam);
        updateteam(&t[t1], g1, g2);
        updateteam(&t[t2], g2, g1);
    }

    return nteam;
}

/* findteam: return corresponded team number with s */
int findteam(char *s, Team *t, int n)
{
    int i;

    for (i = 0; i < n; i++)
        if (strcmp(s, t[i].name) == 0)
            return i;
}

/* updateteam: update team data */
void updateteam(Team *t, int g1, int g2)
{
    t->gp++;
    if (g1 > g2) {
        t->win++;
        t->pt += 3;
    }
    else if (g1 == g2) {
        t->tie++;
        t->pt += 1;
    }
    else
        t->lose++;
    t->gs += g1;
    t->ga += g2;
    t->gd = t->gs - t->ga;
}

/* sort: sort t */
void sort(Team *t, int n)
{
    int i, j;
    Team tmp;

    for (i = 1; i < n; i++)
        for (j = 0; j < i; j++)
            if (t[i].pt != t[j].pt) {
                if (t[i].pt > t[j].pt)
                    SWAP(t[i], t[j], tmp);
            }
            else if (t[i].win != t[j].win) {
                if (t[i].win > t[j].win)
                    SWAP(t[i], t[j], tmp);
            }
            else if (t[i].gd != t[j].gd) {
                if (t[i].gd > t[j].gd)
                    SWAP(t[i], t[j], tmp);
            }
            else if (t[i].gs != t[j].gs) {
                if (t[i].gs > t[j].gs)
                    SWAP(t[i], t[j], tmp);
            }
            else if (t[i].gp != t[j].gp) {
                if (t[i].gp < t[j].gp)
                    SWAP(t[i], t[j], tmp);
            }
            else if (strcasecmp(t[i].name, t[j].name) < 0)
                    SWAP(t[i], t[j], tmp);
}

/* output: output results */
void output(Team *t, int n, char *racename)
{
    int i;

    printf("%s", racename);
    for (i = 0; i < n; i++)
        printf("%d) %s %dp, %dg (%d-%d-%d), %dgd (%d-%d)\n",
               i + 1, t[i].name, t[i].pt, t[i].gp, t[i].win,
               t[i].tie, t[i].lose, t[i].gd, t[i].gs, t[i].ga);
}

ACM 594 One Little, Two Little, Three Little Endians

endian的概念 + 2的補數。
所以正負數的換算可以用:
負數 + 2 ^ x = 正數
正數 - 2 ^ x = 負數
x表示bit數。
以8為一個單位31~24、23~16、15~8、7~0,
轉成7~0、15~8、23~16、31~24的形式即可。
先判斷正負值再做運算,運算後判斷正負值,就可以輸出了。

神人解法

/* ACM 594 One Little, Two Little, Three Little Endians
 * mythnc
 * 2012/01/11 14:19:06   
 * run time: 0.008
 */
#include <stdio.h>
#include <string.h>

#define MAX 32

int convert(int);

int main(void)
{
    int x;

    while (scanf("%d", &x) == 1)
        printf("%d converts to %d\n", x, convert(x));

    return 0;
}

/* convert: convert x to different endian system */
int convert(int x)
{
    int endian[MAX];
    int i, mul;
    
    memset(endian, 0, sizeof(endian));
    if (x < 0) {
        endian[7] = 1;
        x += 2147483647;
        x++;
    }
    i = 24;
    while (x) {
        endian[i++] = x % 2;
        x /= 2;
        if (i % 8 == 0)
            i -= 16;
    }
    for (i = x = 0, mul = 1; i < MAX - 1; i++, mul *= 2)
        x += mul * endian[i];
    if (endian[i] == 1) {
        x -= 2147483647;
        x--;
    }

    return x;
}

ACM 482 Permutation Array

單行資料不定筆。
是說雖然輸入的是浮點數,但是output要print out一模一樣,
也只能用char吃了。

/* ACM 482 Permutation Array
 * mythnc
 * 2012/01/11 12:37:57   
 * run time: 0.008
 */
#include <stdio.h>

#define MAX  1000
#define MAXC 30

int input1(int *);
void input2(int *, char (*)[], int);
void output(char (*)[], int);

int main(void)
{
    int set, n, i;
    int index[MAX];
    char list[MAX][30];

    scanf("%d", &set);
    for (i = 0; i < set; i++) {
        getchar();
        getchar();
        if (i > 0)
            putchar('\n');
        n = input1(index);
        input2(index, list, n);
        output(list, n);
    }

    return 0;
}

/* input1: eat list and return n */
int input1(int *index)
{
    int i;
    char line[MAX];
    char c;

    i = 0;
    while (scanf("%s%c", line, &c) == 2) {
        sscanf(line, "%d", &index[i]);
        i++;
        if (c == '\n')
            return i;
    }
}

/* input2: eat string */
void input2(int *index, char (*list)[MAXC], int n)
{
    int i;

    for (i = 0; i < n; i++)
        scanf("%s", list[index[i] - 1]);
}

/* output: output results */
void output(char (*list)[MAXC], int n)
{
    int i;

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

20120110

ACM 441 Lotto

組合題。
最白爛的方法就是用6個for去寫!
不過如果會用6個for了,那離遞迴解也快了。

/* ACM 441 Lotto
 * mythnc
 * 2012/01/10 21:08:05   
 * run time: 0.008
 */
#include <stdio.h>

#define MAXN 12
#define OUT  6

void input(int n);
void com(int, int, int);

int list[MAXN];
int output[OUT];

int main(void)
{
    int n, set;

    set = 0;
    while (scanf("%d", &n) && n != 0) {
        if (set == 1)
            putchar('\n');
        input(n);
        com(0, n, 0);
        set = 1;
    }

    return 0;
}

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

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

/*
void com1(int *list, int n)
{
    int i, j, k, l, m, o;

    for (i = 0; n - i >= OUT; i++)
        for (j = i + 1; n - j >= OUT - 1; j++)
            for (k = j + 1; n - k >= OUT - 2; k++)
                for (l = k + 1; n - l >= OUT - 3; l++)
                    for (m = l + 1; n - m >= OUT - 4; m++)
                        for (o = m + 1; n - o >= OUT - 5; o++)
                            printf("%d %d %d %d %d %d\n",
                            list[i], list[j], list[k], list[l], list[m], list[o]);
}
*/

/* com: recursive combine to all conditions */
void com(int x, int n, int times)
{
    int i;

    if (times == OUT) {
        printf("%d", output[0]);
        for (i = 1; i < OUT; i++)
            printf(" %d", output[i]);
        putchar('\n');
        return;
    }

    for (i = x; n - i >= OUT - times; i++) {
        output[times] = list[i];
        com(i + 1, n, times + 1);
    }
}

ACM 10341 Solve It

好數學……
是一個Root-finding問題。
因為只分無解跟有一解,所以可以用Bisection method來求解。
EPS至少要設為1e-7才會AC。

algorithmist有詳解。

/* ACM 10341 Solve It
 * mythnc
 * 2012/01/10 20:27:26   
 * run time: 0.064
 */
#include <stdio.h>
#include <math.h>

#define EPS 1e-7

double f(double);
double bisection(void);

int p, q, r, s, t, u;

int main(void)
{
    while (scanf("%d %d %d %d %d %d", &p, &q, &r, &s, &t, &u) == 6)
        if (f(0) * f(1) > 0)
            printf("No solution\n");
        else
            printf("%.4f\n", bisection());

    return 0;
}

double f(double x)
{
    return p * exp(-x) + q * sin(x) + r * cos(x) + s * tan(x) + t * x * x + u;
}

double bisection(void)
{
    double low, high, x;

    low = 0.0;
    high = 1.0;
    while (high - low > EPS) {
        x = (low + high) / 2;
        if (f(low) * f(x) > 0)
            low = x;
        else
            high = x;
    }

    return (low + high) / 2;
}

USACO Calf Flac

Longest Palindromic Substring
不過很gy的是還限制只能比對字母。
是說也可以用暴力枚舉解……。
Z Algorithm真是很威……

/*
ID: mythnc2
LANG: C
TASK: calfflac
2012/01/10 16:44:34   
*/
#include <stdio.h>
#include <string.h>
#include <ctype.h>

#define MAX 20010
#define MIN(X, Y) (X <= Y ? X : Y)

int find(int);
int init(int);
int match(int, int, int);
void print(FILE *, int);

char t[MAX];
char s[MAX * 2];
int z[MAX * 2];

int main (void)
{
    FILE *fin, *fout;
    int c, i, n;

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

    i = 0;
    while ((c = fgetc(fin)) != EOF)
        t[i++] = c;
    t[i] = '\0';

    n = find(i);
    print(fout, n);

    fclose(fin);
    fclose(fout);

    return 0;
}

/* find: find maximum palindrome substring */
int find(int n)
{
    int i, mirror, border, center, right;

    n = init(n);

    /* modified z Algorithm */
    center = right = 0;
    for (i = z[0] = 1; i < n; i++)
        if (i > right) {
            z[i] = match(i, i, n);
            center = i;
            right = i + z[i] - 1;
        }
        else {
            mirror = center - (i - center);
            border = right - i + 1;
            if (z[mirror] == border) {
                z[i] = border + match(i - border, i + border, n);
                center = i;
                right = i + z[i] - 1;
            }
            else
                z[i] = MIN(z[mirror], border);
        }

    return n;
}

/* init: initialize s */
int init(int n)
{
    int i, j;

    memset(s, '.', sizeof(s));
    for (i = j = 0; i < n; i++)
        if (isalpha(t[i])) {
            s[2 * j + 1] = tolower(t[i]);
            j++;
        }

    return 2 * j + 1;
}

/* match: from s[a] to left and from s[b] to right
 * do char compare symmetrically */
int match(int a, int b, int n)
{
    int i;

    i = 0;
    while (a - i >= 0 && b + i < n && s[a - i] == s[b + i])
        i++;

    return i;
}

/* print: print out result */
void print(FILE *fout, int n)
{
    int i, j, pos, from, to, k;

    /* find max len */
    for (i = 1, pos = 0; i < n; ++i)
        if (z[i] > z[pos])
            pos = i;

    /* remove '.' */
    i = pos - (z[pos] - 1);
    if (!(i & 1))
        i++;
    for (n = 0; i <= pos + z[pos] - 1; i += 2, n++)
        s[n] = s[i];

    /* print out len */
    fprintf(fout, "%d\n", n);
    /* print out substring */
    for (i = j = from = to = 0; i < strlen(t); i++)
        if (isalpha(t[i]) && tolower(t[i]) == s[j]) {
            from = k = i;
            while (tolower(t[k]) == s[j] && j < n && k < strlen(t)) {
                j++, k++;
                to = k;
                while (!isalpha(t[k]) && k < strlen(t))
                    k++;
            }
            if (j == n)
                break;
            else
                j = from = to = 0;
        }
    for (i = from; i < to; i++)
        fprintf(fout, "%c", t[i]);
    putc('\n', fout);
}

20120109

ACM 10192 Vacation

ACM10405
/* ACM 10192 Vacation
 * mythnc
 * 2012/01/09 18:05:11
 * run time: 0.004
 */
#include <stdio.h>
#include <string.h>

#define MAXCHAR 102 /* 100 + '\n' + '\0' */
#define MAX(X, Y) (X >= Y ? X : Y)

void lcs(char *, char *, int, int);
/* 0~100: totally 100 + 1 */
int list[MAXCHAR - 1][MAXCHAR - 1];

int main(void)
{
    char s1[MAXCHAR], s2[MAXCHAR];
    int set, n1, n2;

    set = 0;
    while (fgets(s1, MAXCHAR, stdin) && s1[0] != '#') {
        fgets(s2, MAXCHAR, stdin);
        n1 = strlen(s1);
        /* eat '\n' */
        s1[n1] = '\0';
        n1--;
        n2 = strlen(s2);
        s2[n2] = '\0';
        n2--;
        lcs(s1, s2, n1, n2);
        /* output */
        printf("Case #%d: you can visit at most %d cities.\n",
        ++set, list[n1][n2]);
    }

    return 0;
}

/* lcs: use DP to find longest len */
void lcs(char *s1, char *s2, int n1, int n2)
{
    int i, j;
    char tmp[MAXCHAR];

    /* start from [1] to save data */
    /* so move data from 0~n to 1~(n + 1) */
    strcpy(tmp, s1);
    strcpy(s1 + 1, tmp);
    strcpy(tmp, s2);
    strcpy(s2 + 1, tmp);

    /* set list[x][0] and list[0][x] to zero */
    for (i = 0; i <= n1; i++)
        list[i][0] = 0;
    for (i = 1; i <= n2; i++)
        list[0][i] = 0;

    for (i = 1; i <= n1; i++)
        for (j = 1; j <= n2; j++)
            if (s1[i] == s2[j])
                list[i][j] = list[i - 1][j - 1] + 1;
            else
                list[i][j] = MAX(list[i - 1][j], list[i][j - 1]);
}


ACM 10066 The Twin Towers

Longest Common Subsequence,
ACM10405,不多贅述。

/* ACM 10066 The Twin Towers
 * mythnc
 * 2012/01/09 17:14:48   
 * run time: 0.008
 */
#include <stdio.h>

#define MAXN 101
#define MAX(X, Y) (X >= Y ? X : Y)

void input(int *, int);
void lcs(int *, int *, int, int);
void print(int, int);

int list[MAXN][MAXN];

int main(void)
{
    int set, n1, n2;
    int s1[MAXN], s2[MAXN];

    set = 0;
    while (scanf("%d %d", &n1, &n2) == 2 && n1 != 0) {
        input(s1, n1);
        input(s2, n2);
        lcs(s1, s2, n1, n2);
        print(++set, list[n1][n2]);
    }

    return 0;
}

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

    /* start from [1] to save data */
    for (i = 1;i <= n; i++)
        scanf("%d", &s[i]);
}

/* lcs: use dp to find longest length */
void lcs(int *s1, int *s2, int n1, int n2)
{
    int i, j;

    /* set list[x][0] and list[0][x] to zero */
    for (i = 0; i <= n1; i++)
        list[i][0] = 0;
    for (i = 1; i <= n2; i++)
        list[0][i] = 0;

    /* i, j is equal to e1, e2 */
    for (i = 1; i <= n1; i++)
        for (j = 1; j <= n2; j++)
            if (s1[i] == s2[j]) /* e1 = e2: do LCS(sub1, sub2) + e1 */
                list[i][j] = list[i - 1][j - 1] + 1; /* + 1 mean e1 */
            else /* e1 != e2: do max(LCS(sub1, s2), sub2(s1, sub2)) */
                list[i][j] = MAX(list[i - 1][j], list[i][j - 1]);
}

/* print: print out result */
void print(int set, int value)
{
    printf("Twin Towers #%d\n", set);
    printf("Number of Tiles : %d\n\n", value);
}

ACM 111 History Grading

ACM10405

唯要注意
Given the correct chronological order of n events 1, 2, 3, ... , n
as c1, c2, c3, ... , cn where 1 <= ci <= n denotes the ranking of event i in the correct chronological order
表示位置本身是事件,
而數字的意義是發生的次序先後。
好比1 4 5 3 2表示
事件1第1個發生,
事件2第4個發生,
事件3第5個發生,
事件4第3個發生,
事件5第2個發生;
而非第1個發生的是事件1,
第2個發生的是事件4,
第3個發生的是事件5,
第4個發生的是事件3,
第5個發生的是事件2。
反過來想就對啦!

/* ACM 111 History Grading
 * mythnc
 * 2012/01/09 16:13:15   
 * run time: 0.016
 */
#include <stdio.h>

#define MAXN  21
#define TRUE  1
#define FALSE 0
#define MAX(X, Y) (X >= Y ? X : Y)

int input(int *, int);
void lcs(int *, int *, int);

int list[MAXN][MAXN];

int main(void)
{
    int n;
    int correct[MAXN], test[MAXN];

    scanf("%d", &n);
    input(correct, n);
    while (input(test, n)) {
        lcs(correct, test, n);
        printf("%d\n", list[n][n]);
    }

    return 0;
}

/* input: receive input data */
int input(int *seq, int n)
{
    int i, pos;

    /* start from [1] to save data */
    for (i = 1; i <= n; i++) {
        if (scanf("%d", &pos) != 1)
            return FALSE;
        seq[pos] = i;
    }

    return TRUE;
}

/* lcs: use dp to find longest length */
void lcs(int *s1, int *s2, int n)
{
    int i, j;

    /* set list[x][0] and list[0][x] to zero */
    for (i = 0; i <= n; i++)
        list[i][0] = list[0][i] = 0;

    /* i, j is equal to e1, e2 */
    for (i = 1; i <= n; i++)
        for (j = 1; j <= n; j++)
            if (s1[i] == s2[j]) /* e1 = e2: do LCS(sub1, sub2) + e1 */
                list[i][j] = list[i - 1][j - 1] + 1; /* + 1 mean e1 */
            else /* e1 != e2: do max(LCS(sub1, s2), sub2(s1, sub2)) */
                list[i][j] = MAX(list[i - 1][j], list[i][j - 1]);
}

ACM 10405 Longest Common Subsequence

標準Longest Common Subsequence找最長字串題。
詳細的演算法可以看這裡
不再贅述。

input要以行為單位,
意思就是space也要列入處理。

/* ACM 10405 Longest Common Subsequence
 * mythnc
 * 2012/01/09 13:40:53   
 * run time: 0.024
 */
#include <stdio.h>
#include <string.h>

#define MAXCHAR 1002 /* 1000 + '\n' + '\0' */
#define MAX(X, Y) (X >= Y ? X : Y)

void lcs(char *, char *, int, int);

int list[MAXCHAR][MAXCHAR];

int main(void)
{
    char s1[MAXCHAR], s2[MAXCHAR];
    int n1, n2;

    while (fgets(s1, MAXCHAR, stdin)) {
        fgets(s2, MAXCHAR, stdin);
        n1 = strlen(s1);
        /* eat '\n' */
        s1[n1] = '\0';
        n1--;
        n2 = strlen(s2);
        s2[n2] = '\0';
        n2--;
        lcs(s1, s2, n1, n2);
        printf("%d\n", list[n1][n2]);
    }

    return 0;
}

/* lcs: use DP to find longest len */
void lcs(char *s1, char *s2, int n1, int n2)
{
    int i, j;
    char tmp[MAXCHAR];

    /* start from [1] to save data */
    /* so move data from 0~n to 1~(n + 1) */
    strcpy(tmp, s1);
    strcpy(s1 + 1, tmp);
    strcpy(tmp, s2);
    strcpy(s2 + 1, tmp);

    /* set list[x][0] and list[0][x] to zero */
    for (i = 0; i <= n1; i++)
        list[i][0] = 0;
    for (i = 1; i <= n2; i++)
        list[0][i] = 0;

    for (i = 1; i <= n1; i++)
        for (j = 1; j <= n2; j++)
            if (s1[i] == s2[j])
                list[i][j] = list[i - 1][j - 1] + 1;
            else
                list[i][j] = MAX(list[i - 1][j], list[i][j - 1]);
}

ACM 11727 Cost Cutting

sort之後找median即可。

/* ACM 11727 Cost Cutting
 * mythnc
 * 2012/01/09 10:24:42   
 * run time: 0.004
 */
#include <stdio.h>

#define MAXP 3

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

int main(void)
{
    int i, n;
    int list[MAXP];

    scanf("%d", &n);
    for (i = 1; i <= n; i++) {
        scanf("%d %d %d", list, list + 1, list + 2);
        qsort(list, MAXP, sizeof(int), cmp);
        printf("Case %d: %d\n", i, list[1]);
    }

    return 0;
}

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

20120108

ACM 195 Anagram

ACM10098
除了排列方式不同,其他都一樣。
要A > a > B > b > ... > Z > z的順序做排列。
所以先排成他要的這種形式再做backtracking。

/* ACM 195 Anagram
 * mythnc
 * 2012/01/08 21:33:59   
 * run time: 0.044
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXCHAR 1000
#define TRUE    1
#define FALSE   0

void sort(char *, int);
void backtrack(int);
int cmp(const void *a, const void *b);

char input[MAXCHAR], output[MAXCHAR];
int visited[MAXCHAR];

int main(void)
{
    scanf("%*d");
    while (scanf("%s", &input) == 1) {
        sort(input, strlen(input));
        backtrack(0);
    }

    return 0;
}

/* sort: sort s in alphabetically order:
 * A > a > B > b > .... > Z > z */
void sort(char *s, int n)
{
    char upper[MAXCHAR], lower[MAXCHAR];
    int i, j, k, up, low;

    for (i = up = low = 0; i < n; i++)
        if (s[i] >= 'A' && s[i] <= 'Z')
            upper[up++] = s[i];
        else
            lower[low++] = s[i];
    /* sort each array */
    qsort(upper, up, sizeof(char), cmp);
    qsort(lower, low, sizeof(char), cmp);
    i = j = k = 0;
    /* copy back to s (in sorted order) */
    while (k < low && j < up)
        if (lower[k] - 'a' + 'A' < upper[j])
            s[i++] = lower[k++];
        else
            s[i++] = upper[j++];
    while (k < low)
            s[i++] = lower[k++];
    while (j < up)
            s[i++] = upper[j++];
}

/* backtrack: do backtrack to producing answer */
void backtrack(int i)
{
    int j;

    /* output */
    if (input[i] == '\0') {
        output[i] = '\0';
        printf("%s\n", output);
        return;
    }
    /* clear the previous content in output[i] */
    output[i] = -1;
    for (j = 0; input[j] != '\0'; j++)
        if (!visited[j] && input[j] != output[i]) {
            visited[j] = TRUE;
            output[i] = input[j];
            backtrack(i + 1);
            visited[j] = FALSE;
        }
}

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

ACM 10098 Generating Fast

排列組合之排列的標準題型。
我覺得還滿難的……
由於要按照字母排列順序輸出,且重複字母需列入考慮,
不是只是輸出所有情況而已……

使用backtracking的方法解題。
感覺是dfs的變形體,把每個字母當成一個節點看待。
每次都取其中一個節點,接著遞迴取第二個節點,直到每個節點皆取畢為止。

所以其實要做的很簡單……就是做從節點1到節點n,每個點都去做dfs。
光是紀錄是否已經走訪已經可以排出非重複字母的所有排列情況。
現在在把重複的情況納入考慮。
一個偷吃步的方法,就是對原本的string做sort,
sort後的string會依照大小順序排列。
如此,每當遇到一個重複的情況,就去對比原本存在output上的值是否相等,
若相等,表示重複,就跳過,不做dfs。
用講的感覺很抽象,直接舉實例:
若input為abcdc,先做sort後為:abccd。
假設5個節點為a b c1 c2 d,
按照順序,從a開始對每個節點遞迴做dfs。
a -> b -> c1 -> c2 -> d,這是第一次。
a -> b -> c1 -> c2 -> 沒點了,back,
a -> b -> c1 -> d -> c2,第二次,
a -> b -> c1 -> d -> 沒點了,back,
a -> b -> 這時候按照順序應該要取c2,但是c1跟c2兩個節點的內容都是c,
所以就不取,跳過c2,取d。

所以這就是為什麼要先做sort的原因,因為按照順序排列,
可以確定接下來要取的點是否與上一點重複。
如果沒有先sort,那是無法判別重複的(以此方法而言)。

或許還有其他更好的方法……歡迎提供。
筆者才疏學淺,一個方法都沒想到……
(沒錯,這個方法也是我在網路上看到的,世界真是充滿一堆神人 + 神碼)

/* ACM 10098 Generating Fast
 * mythnc
 * 2012/01/08 22:17:54
 * run time: 0.108
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define MAXCHAR 11
#define TRUE    1
#define FALSE   0

void backtrack(int);
int cmp(const void *a, const void *b);

char input[MAXCHAR], output[MAXCHAR];
int visited[MAXCHAR];

int main(void)
{
    scanf("%*d");
    while (scanf("%s", &input) == 1) {
        qsort(input, strlen(input), sizeof(char), cmp);
        backtrack(0);
        putchar('\n');
    }

    return 0;
}

/* backtrack: do backtrack to producing answer */
void backtrack(int i)
{
    int j;

    /* output */
    if (input[i] == '\0') {
        output[i] = '\0';
        printf("%s\n", output);
        return;
    }
    /* clear the previous content in output[i] */
    output[i] = -1;
    for (j = 0; input[j] != '\0'; j++)
        if (!visited[j] && input[j] != output[i]) {
            visited[j] = TRUE;
            output[i] = input[j];
            backtrack(i + 1);
            visited[j] = FALSE;
        }
}

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

ACM 146 ID Codes

本來想用排列組合的方式去解,
只要排到跟input相等的組合,
下一次的排列組合就是答案。
不過沒想到竟然TL了 =.=。

所以得想一個更快的方法才行:
直接排!就是最快的方式!

至於如何直接排呢?
可以參考algorithmist的方法。
主要是從右邊開始往左找,找到第一組string[y] < string[x]的情況時,
就把string[x]與string[y]對調,x~y之間的substring與x~strlen(n)間的substring
做reverse後,兩者互換即可。

證明
... y ...(1)... x ...(2)...
由s[y] < s[x]可推導出,
substring(2) <= s[y] < s[x],
substring(1) >= s[x] > s[y]。
若要按照字母順序排列,
那下一筆資料就需比s[y]大且要在s[y]之後,
兩者之間不可有其他元素。
s[x]是唯一選擇,
所以x與y互換。
... x ...(1)... y ...(2)...
這時候(1)、y與(2)三者要排列要為最小順序,
讓x~y之間的substring <= y <= y之後的substring。
由推導出的公式可知,
substring(2) <= s[y],
substring(1) >= s[y],
所以substring(2)要排在y前面,
substring(1)排在y後面。
但是substring(1)與substring(2)兩者排列也要為最小順序,
所以需把(1)與(2)做reverse。

簡單講呢,就是reverse中做reverse啦。
x與y互換之後(1)y(2)變成,(2)y(1),
(2)跟(1)再做reverse,可得
... x ...~(2)... y ...~(1)...

/* ACM 146 ID Codes
 * mythnc
 * 2012/01/08 19:16:00   
 * run time: 0.000
 */
#include <stdio.h>
#include <string.h>

#define MAXCHAR 51
#define TRUE    1
#define FALSE   0

void next(char *, int);
void reverse(char *, int, int, char *);

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

    while (scanf("%s", input) && input[0] != '#')
        next(input, strlen(input));

    return 0;
}

/* next: find next permutation of s */
void next(char *s, int n)
{
    int i, j, last;
    char x, y;
    char wl[MAXCHAR], wr[MAXCHAR];

    for (i = n - 1, last = TRUE; i > 0; i--) {
        for (j = i - 1; j > -1; j--)
            if (s[j] < s[i]) {
                last = FALSE;
                break;
            }
        if (!last)
            break;
    }

    /* s is the last */
    if (last) {
        printf("No Successor\n");
        return;
    }

    wl[0] = wr[0] = '\0';
    if (i - j > 1)
        reverse(s, j, i, wl);
    if (n - i > 1)
        reverse(s, i, n, wr);

    /* output */
    x = s[i];
    y = s[j];
    s[j] = '\0';
    printf("%s%c%s%c%s\n", s, x, wr, y, wl);
}

/* reverse: reverse s from start to end.
 * save result in t */
void reverse(char *s, int start, int end, char *t)
{
    int i, j;

    for (i = end - 1, j = 0; i > start; i--, j++)
        t[j] = s[i];

    t[j] = '\0';
}

20120107

ACM 105 The Skyline Problem

本來想直接做,但是要考慮很多很多問題。
就算是input已經sorted,要考慮起始點跟終點。
起始點是否相等,紀錄前後起始點;
終點處理,暫存等等等……頭都昏惹。

後來看到神人的解法……只有佩服兩個字可以形容。
首先我們已知最高高度跟最長長度。
假設一開始只有一塊土地,啥建築物都沒有。
現在每吃到一筆資料(一棟建築物),就更新我們的skyline,
如此,隨著建築物不停的增加,天際線也會不斷的改變。
最後再輸出天際線即可。
真是個強大的方法……

/* ACM 105 The Skyline Problem
 * mythnc
 * 2012/01/07 09:19:19   
 * run time: 0.02
 */
#include <stdio.h>

#define MAXH 10000

typedef struct build {
    int s, e, h;
} Build;

void update(Build);
void print(void);

int sky[MAXH];

int main(void)
{
    Build x;

    while (scanf("%d %d %d", &x.s, &x.h, &x.e) == 3)
        update(x);
    print();

    return 0;
}

/* update: update sky line */
void update(Build x)
{
    int i;

    for (i = x.s; i < x.e; i++)
        if (x.h > sky[i])
            sky[i] = x.h;
}

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

    /* find the first building */
    for (i = h = 0; i < MAXH; i++)
        if (sky[i] != h) {
            printf("%d %d", i, sky[i]);
            h = sky[i];
            break;
        }
    for (; i < MAXH; i++)
        if (sky[i] != h) {
            printf(" %d %d", i, sky[i]);
            h = sky[i];
        }
    putchar('\n');
}

20120105

ACM 11547 AUTOMATIC ANSWER

直接做……
做完運算後的值若是負數,要先變為正數。
再取十位數即可。

/* ACM 11547 AUTOMATIC ANSWER
 * mythnc
 * 2012/01/05 21:01:17   
 * run time: 0.008
 */
#include <stdio.h>

int ans(int);

int main(void)
{
    int n;

    scanf("%*d");
    while (scanf("%d", &n) == 1)
        printf("%d\n", ans(n));

    return 0;
}

/* ans: find the answer and return tens column */
int ans(int n)
{
    n = (n * 567 / 9 + 7492) * 235 / 47 - 498;
    if (n < 0)
        n = -n;

    return n % 100 / 10;
}

ACM 108 Maximum Sum

難題……直接用暴力硬幹會花O(n ^ 6)的時間,直接TL =.=。
後來查了很多資料,看人家的想法等等。
才發現到,原來Maximum subarray problem
已經有人在研究。一維list,可以用O(n)就找出max sum。
這個方法稱為Kadane's algorithm。
而二維套用一維的概念,就可以花O(n ^ 3)的時間找出max sum。
解法主要參考這裡
另外要講一下,algorithmist的解法應該是正確的,
但是prefix sum應該會花O(n ^ 3)的時間建立。我覺得algorithmist寫得太簡略,
以至於讓人看不懂(或是誤解)。

主要想法:對於一維陣列,
我們可以使用Kadane's algorithm以O(n)的方式求出max sum。
所以二維陣列,可以用一維陣列的方式求解。
例如題目給的陣列
0 -2 -7 0 (1)
9 2 -6 2 (2)
-4 1 -4 1 (3)
-1 8 0 -2 (4)
其實可以看成10個子陣列(皆一維)
這些陣列分別是
(1)、(1) + (2)、(1) + (2) + (3)、(1) + (2) + (3) + (4)、
(2)、(2) + (3)、(2) + (3) + (4)、
(3)、(3) + (4)、
(4)。
從這十個一維陣列中找出max sum,即是答案。
建立子陣列需要花O(n ^ 2)的時間,而每個陣列需要花O(n)的時間找sum。
所以總共要花O(n ^ 3)的時間。

Kadane's algorithm滿像我解ACM661找最大電流的方法,
不過Kadane's algorithm更精確……令人佩服!
Kadane's algorithm的說明可以看wiki python實作,
或是Algorithm的code實作,
可以一目了然其運作原理。
這裡也有解釋Kadane's algorithm。
(但不要看他的code,是錯的……雖然AC)
uva toolkit的output也是錯的……。

/* ACM 108 Maximum Sum
 * mythnc
 * 2011/10/28 21:31:21   
 * run time: 0.008
 */
#include <stdio.h>
#include <string.h>

#define MAXN 100

void subsum(int, int);

int s[MAXN][MAXN];
int colsum[MAXN];
int max;

int main(void)
{
    int n, i, j;

    scanf("%d", &n);
    /* init */
    for (i = 0; i < n; i++)
        for (j = 0; j < n; j++)
            scanf("%d", &s[i][j]);

    max = -12701;
    for (i = 0; i < n; i++) {
        for (j = i; j < n; j++)
            subsum(j, n);
        /* clear colsum's content */
        memset(colsum, 0, sizeof(int) * n);
    }

    printf("%d\n", max);

    return 0;
}

/* subsum: calculate the sub-rectangle value */
void subsum(int row, int n)
{
    int i, j, sum;

    for (i = 0; i < n; i++)
        colsum[i] += s[row][i];
    /* Kadane's algorithm (modified) */
    for (i = sum = 0; i < n; i++) {
        sum += colsum[i];
        if (sum > max)
            max = sum;
        if (sum < 0)
            sum = 0;
    }
}

20120104

ACM 11498 Division of Nlogonia

直接做,判斷值與基準點的差。
依據差值可以知道該值所在的象限位置。

/* ACM 11498 Division of Nlogonia
 * mythnc
 * 2012/01/04 19:37:29   
 * run time: 0.012
 */
#include <stdio.h>

typedef struct coor {
    int x, y;
} Coordinates;

void output(Coordinates, int);

int main(void)
{
    int n;

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

    return 0;
}

/* output: find the x in which quadrant
 * and output answer */
void output(Coordinates d, int n)
{
    Coordinates d, i, sub;

    scanf("%d %d", &d.x, &d.y);
    while (n--) {
        scanf("%d %d", &i.x, &i.y);
        sub.x = i.x - d.x;
        sub.y = i.y - d.y;
        if (sub.x == 0 || sub.y == 0)
            printf("divisa\n");
        else if (sub.x > 0 && sub.y > 0)
            printf("NE\n");
        else if (sub.x < 0 && sub.y > 0)
            printf("NO\n");
        else if (sub.x < 0 && sub.y < 0)
            printf("SO\n");
        else if (sub.x > 0 && sub.y < 0)
            printf("SE\n");
    }
}


ACM 11150 Cola

ACM10346,不過是簡單版,但多了一個條件。
當剩下的瓶子再 + 1,若可被3整除,則最大值 + 1。

是說這題ACM還畫圖給提示耶……是說每題ACM都這麼nice就好了。

/* ACM 11150 Cola
 * mythnc
 * 2012/01/04 17:25:04   
 * run time: 0.008
 */
#include <stdio.h>

int change(int);

int main(void)
{
    int n;

    while (scanf("%d", &n) == 1)
        printf("%d\n", change(n));

    return 0;
}

/* change: return the max colas we can get
 * from this change mechanism */
int change(int n)
{
    int sum;

    sum = n;
    while (n >= 3) {
        sum += n / 3;
        n = n / 3 + n % 3;
    }
    if (n == 2)
        sum++;

    return sum;
}

ACM 11044 Searching for Nessy

很有趣的題目,
之前玩解謎遊戲有解到。
其實直接去填圖就是最佳解。
正規的解法:ceil(長 / 3) * ceil(寬 / 3)。
所以此題的解應該是ceil((h - 2) / 3) * ceil((w - 2) / 3),
不過x / 3與ceil((x - 2) / 3)的解相同。
所以(h / 3) * (w / 3)就是答案。

/* ACM 11044 Searching for Nessy
 * mythnc
 * 2012/01/04 16:59:37   
 * version2: optimization v1
 * run time: 0.008
 */
#include <stdio.h>

int main(void)
{
    int m, n;

    scanf("%*d");
    while (scanf("%d %d", &m, &n) == 2)
        printf("%d\n", (m / 3) * (n / 3));

    return 0;
}

ACM 10363 Tic Tac Toe

檢驗圈圈叉叉的圖形是否合法。

一開始想的很簡單,
考慮不全,連吃幾次WA。
重點如下:
1. X先下。所以X要嘛跟O相等,要嘛比O多1。
2. O勝利的情況,至多一條線且X跟O需相等。
3. X勝利的情況
(a)兩條線,X要多O一個,且九格皆佔滿。
(b)一條線,X要多O一個。
4.不會有O勝利且X勝利的情況。

每次否定邏輯語句我都會把&&跟||用錯 =.=,
狄摩根定律跟括號問題……Orz

/* ACM 10363 Tic Tac Toe
 * mythnc
 * 2012/01/04 14:26:07   
 * run time: 0.012
 */
#include <>

#define SQUARE 3
#define TRUE   1
#define FALSE  0 

void input(char (*)[]);
int legal(char (*)[]);

int main(void)
{
    char tic[SQUARE][SQUARE + 1];
    int n, i;

    scanf("%d", &n);
    for (i = 0; i < n; i++) {
        input(tic);
        if (legal(tic))
            printf("yes\n");
        else
            printf("no\n");
    }

    return 0;
}

/* input: receive input data */
void input(char (*t)[SQUARE + 1])
{
    int i;

    for (i = 0; i < 3; i++)
        scanf("%s", t[i]);
}

/* legal: if square is legal return TRUE
 * else return FALSE */
int legal(char (*t)[SQUARE + 1])
{
    int counto, countx, linex, lineo;
    int i, j;

    for (counto = countx = i = 0; i < 3; i++)
        for (j = 0; j < 3; j++)
            if (t[i][j] == 'O')
                counto++;
            else if (t[i][j] == 'X')
                countx++;
    /* if X - O is not 1 or 0 is illegal */
    if (!(countx - counto == 0 || countx - counto == 1))
        return FALSE;
    /* vertical and horizontal line */
    for (i = lineo = linex = 0; i < 3; i++) {
        if (t[i][0] == t[i][1] && t[i][1] == t[i][2])
            if (t[i][0] == 'O')
                lineo++;
            else if (t[i][0] == 'X')
                linex++;
        if (t[0][i] == t[1][i] && t[1][i] == t[2][i])
            if (t[0][i] == 'O')
                lineo++;
            else if (t[0][i] == 'X')
                linex++;
    }
    /* diagonal line */
    if (t[0][0] == t[1][1] && t[1][1] == t[2][2])
        if (t[1][1] == 'O')
            lineo++;
        else if (t[1][1] == 'X')
            linex++;
    if (t[2][0] == t[1][1] && t[1][1] == t[0][2])
        if (t[1][1] == 'O')
            lineo++;
        else if (t[1][1] == 'X')
            linex++;

    if (lineo > 1 || linex > 2)
        return FALSE;
    if (lineo == 1 && !(linex == 0 && counto == countx))
        return FALSE;
    if (linex == 1 && !(lineo == 0 && countx - counto == 1))
        return FALSE;
    if (linex == 2 && !(lineo == 0 && countx + counto == 9))
        return FALSE;

    return TRUE;
}

ACM 739 Soundex Indexing

做map跟處理output。

先讓soundex與字母做map。
不處理map後為0跟map後與前一個字母有相同map值的情況。
output要特別處理一下,值得一提的是:
printf("%*s\n", max, s);
max對應*,s對應s。
如此可以自由控制縮排。

/* ACM 739 Soundex Indexing
 * mythnc
 * 2012/01/04 11:35:35   
 * run time: 0.024
 */
#include <stdio.h>
#include <string.h>

#define LINEMAX 20

void map(char *, char *);

int main(void)
{
    char name[LINEMAX];
    char encode[5];

    printf("%9c%s%*c%s\n", ' ', "NAME", 25 - strlen("NAME"), ' ', "SOUNDEX CODE");
    while (scanf("%s", name) == 1) {
        map(name, encode);
        printf("%9c%s%*c%s\n", ' ', name, 25 - strlen(name), ' ', encode);
    }
    printf("%19c%s\n", ' ', "END OF OUTPUT");

    return 0;
}

/* map: map name to its correspond code */
void map(char *name, char *encode)
{
    int i, j;
    int table[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};

    encode[0] = name[0];
    for (i = 1, j = 1; j < strlen(name) && i < 4; j++) {
        if (table[name[j] - 'A'] == 0
            || table[name[j] - 'A'] == table[name[j - 1] - 'A'])
            continue;
        encode[i++] = table[name[j] - 'A'] + '0';
    }
    while (i < 4)
        encode[i++] = '0';
    encode[i] = '\0';
}

20120103

ACM 661 Blowing Fuses

直接做……就只是個算安培……
開關打開要紀錄最高安培數即可。

/* ACM 661 Blowing Fuses
 * mythnc
 * 2012/01/03 23:17:33   
 * run time: 0.004
 */
#include <stdio.h>

#define MAXN 20
#define ON   1
#define OFF  0

typedef struct device {
    int state;
    int c;
} Device;

int maxpower(int, int);

int main(void)
{
    int n, m, c, max, set;

    set = 0;
    while (scanf("%d %d %d", &n, &m, &c) && n != 0) {
        max = maxpower(n, m);
        if (max > c)
            printf("Sequence %d\nFuse was blown.\n\n", ++set);
        else {
            printf("Sequence %d\nFuse was not blown.\n", ++set);
            printf("Maximal power consumption was %d amperes.\n\n", max);
        }
    }

    return 0;
}

/* maxpower: return the max consumption power
 * during the sequence*/
int maxpower(int n, int m)
{
    int max, i, number, sum;
    Device dev[MAXN];
    /* init */
    for (i = 0; i < n; i++) {
        scanf("%d", &dev[i].c);
        dev[i].state = OFF;
    }
    /* switch start */
    for (i = max = sum = 0; i < m; i++) {
        scanf("%d", &number);
        if (dev[number - 1].state == ON) {
            dev[number - 1].state = OFF;
            sum -= dev[number - 1].c;
        }
        else {
            dev[number - 1].state = ON;
            sum += dev[number - 1].c;
            if (max < sum)
                max = sum;
        }
    }

    return max;
}

ACM 10420 List of Conquests

有點像千人斬 XD

兩種情況:
愛人可能重複或不重複。
如果不會重複,直接做binary search tree就可以了;
如果會重複除了binary search tree之外,還要對名字做紀錄。

token的處理,我用sscanf()先吃掉一個,再用strcpy()把第一個以後的往前copy。
因為不知道資料有多少筆,就用動態的方式存資料。
沒特別針對名字做最佳化,如果sort後再用binary search理當快一點。

最後其實資料是不會重複的,所以直接做binary search tree就好了。

/* ACM 10420 List of Conquests
 * mythnc
 * 2012/01/03 10:19:51   
 * run time: 0.016
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define LINEMAX 80
#define MAXCHAR 20

typedef struct woman {
    char *name;
    struct woman *next;
} Woman;

typedef struct node {
    char country[MAXCHAR];
    int count;
    Woman *list;
    struct node *left, *right;
} Tnode;

void token(char *, char *);
Tnode *addtree(Tnode *, char *, char *);
Woman *addwoman(Woman *, char *, int *);
void printtree(Tnode *);
void freetree(Tnode *);

int main(void)
{
    char name[LINEMAX];
    char country[MAXCHAR];
    Tnode *root;

    root = NULL;
    scanf("%*d");
    getchar();
    while (fgets(name, LINEMAX, stdin)) {
        token(country, name);
        root = addtree(root, country, name);
    }
    printtree(root);
    freetree(root);

    return 0;
}

/* token: split name to country and woman name */
void token(char *country, char *name)
{
    char *pt;

    sscanf(name, "%s", country);
    pt = name + strlen(country);
    while (*pt == ' ')
        pt++;
    strcpy(name, pt);
    pt = name + strlen(name);
    while (*(pt - 1) == '\n' || *(pt - 1) == ' ')
        pt--;
    *pt = '\0';
}

/* addtree: add country and name into bin search tree */
Tnode *addtree(Tnode *pt, char *country, char *name)
{
    int i;

    if (pt == NULL) {
        pt = (Tnode *)malloc(sizeof(Tnode));
        strcpy(pt->country, country);
        pt->left = pt->right = NULL;
        pt->count = 0;
        pt->list = NULL;
        pt->list = addwoman(pt->list, name, &pt->count);
    }
    else if ((i = strcmp(country, pt->country)) == 0)
        pt->list = addwoman(pt->list, name, &pt->count);
    else if (i < 0)
        pt->left = addtree(pt->left, country, name);
    else
        pt->right = addtree(pt->right, country, name);

    return pt;
}

/* addwoman: add woman name into list */
Woman *addwoman(Woman *head, char *name, int *count)
{
    Woman *pt;

    for (pt = head; pt; pt = pt->next)
        if (strcmp(pt->name, name) == 0)
            return head;

    pt = (Woman *)malloc(sizeof(Woman));
    pt->next = NULL;
    pt->name = (char *)malloc(strlen(name) + 1);
    strcpy(pt->name, name);
    ++*count;
    
    return head;
}

/* printtree: print out bin search tree */
void printtree(Tnode *pt)
{
    if (pt == NULL)
        return;

    printtree(pt->left);
    printf("%s %d\n", pt->country, pt->count);
    printtree(pt->right);
}

/* freetree: free() all nodes */
void freetree(Tnode *pt)
{
    Woman *tmp;

    if (pt == NULL)
        return;

    freetree(pt->left);
    freetree(pt->right);
    while (pt->list) {
        tmp = pt->list;
        pt->list = pt->list->next;
        free(tmp->name);
        free(tmp);
    }
    free(pt);
}

20120102

ACM 10195 The Knights Of The Round Table

利用海龍公式與內接圓半徑公式,
就可求得半徑r。

內接圓半徑 = 2 * S / (a + b + c)
p = (a + b + c) / 2代入,S用海龍代入。
化簡可得
√[(p - a) * (p - b) * (p - c) / p]。

唯一要注意的是,input可能為0,
這時候不構成三角形,因此也沒有所謂的內接圓半徑。
(WTF)

/* ACM 10195 The Knights Of The Round Table
 * mythnc
 * 2012/01/02 09:56:51   
 * run time: 0.008
 */
#include <stdio.h>
#include <math.h>

double radius(double, double, double);

int main(void)
{
    double a, b, c;

    while (scanf("%lf %lf %lf", &a, &b, &c) == 3)
        printf("The radius of the round table is: %.3f\n", radius(a, b, c));

    return 0;
}

double radius(double a, double b, double c)
{
    double p;
    
    if (a == 0.0 || b == 0.0 || c == 0.0)
        return 0.0;

    p = (a + b + c) / 2.0;

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

20120101

ACM 408 Uniform Generator

complete search。
從0到mod - 1,探訪過的就做紀錄,
到第二次探訪時就停止。
比對探訪次數是否等於m即可。

法2:求step與mod是否互質也可。

/* ACM 408 Uniform Generator
 * mythnc
 * 2012/01/01 10:07:53   
 * run time: 0.068
 */
#include <stdio.h>
#include <string.h>

#define MAXMOD 10000000
#define TRUE   1
#define FALSE  0

int complete(int, int);

int visited[MAXMOD];

int main(void)
{
    int step, mod;

    while (scanf("%d %d", &step, &mod) == 2)
        if (complete(step, mod))
            printf("%10d%10d    Good Choice\n\n", step, mod);
        else
            printf("%10d%10d    Bad Choice\n\n", step, mod);

    return 0;
}

/* complete: return TRUE if s and m will
 * generate all numbers between 0 to m - 1
 * else return FALSE */
int complete(int s, int m)
{
    int count, x;

    s %= m;
    x = count = 0;
    while (!visited[x]) {
        visited[x] = TRUE;
        count++;
        x = (x + s) % m;
    }
    memset(visited, 0, sizeof(int) * m);

    if (count == m)
        return TRUE;
    return FALSE;
}