2012-09-26 22:19:29Morris

[ITSA] 17th 總解答

第一題 模擬

#include <stdio.h>

int main() {
    int n;
    while(scanf("%d", &n) == 1) {
        int sk1[100], sk2[100];
        int idx = -1, i;
        int tot = 0, p = 0, v, w;
        int vv[100], ww[100];
        for(i = n-1; i >= 0; i--)
            scanf("%d %d", &vv[i], &ww[i]);
        for(i = 0; i < n; i++) {
            v = vv[i], w = ww[i];
            if(tot+w <= 20) {
                ++idx;
                sk1[idx] = v, sk2[idx] = w;
                tot += w, p += v;
            } else {
                if((double)sk1[idx]/sk2[idx] > (double)v/w) continue;
                if((double)sk1[idx]/sk2[idx] < (double)v/w) {
                    tot -= sk2[idx], p -= sk1[idx];
                    sk1[idx] = v, sk2[idx] = w;
                    tot += w, p += v;
                }
            }
        }
        printf("%d %d\n", p, tot);
    }
    return 0;
}

第二題 求最大獨立集 dfs 回朔求解

#include <stdio.h>
#include <string.h>
int ans = 0, n, m;
int g[105][105], gt[105];
int used[105] = {};
void dfs(int idx, int v) {
    if(v > ans) ans = v;
    if(v + n-idx < ans)
        return;
    if(idx == n)
        return;
    int i = 0, can = 0;
    for(i = 0; i < gt[idx]; i++) {
        if(used[g[idx][i]])
            break;
    }
    if(i == gt[idx])    can = 1;
    if(can) {
        used[idx] = 1;
        dfs(idx+1, v+1);
        used[idx] = 0;
    }
    dfs(idx+1, v);
}
int main() {
    int i, x, y;
    while(scanf("%d %d", &m, &n) == 2) {
        for(i = 0; i < m; i++) {
            scanf("%d %d", &x, &y);
            g[x][gt[x]++] = y;
            g[y][gt[y]++] = x;
        }
        ans = 0;
        dfs(0, 0);
        printf("%d\n", ans);
    }
    return 0;
}

第三題 時間計算, 模擬

#include <cstdio>

int main() {
    int t;
    scanf("%d", &t);
    while(t--) {
        int H, M, h, m, s, d;
        scanf("%d %d %d %d %d %d", &H, &M, &h, &m, &s, &d);
        H = H*60+M;
        h = h*60+m;
        H = h-H;
        if(H%60)    H = H/60+1;
        else    H = H/60;
        printf("%d\n", H*d*s);
    }
    return 0;
}

第四題 前序運算式, 建造一棵運算樹 (其實我忘記他的學術名稱), 總之只有葉節點是值, 非葉節點都是運算子(+-*/), 接著藉由樹的走訪可以輸出跟計算答案

#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string.h>
using namespace std;
typedef struct {
    int l, r;
    int num;
    int flag;
} Node;
Node Nd[1000];
int size;
stringstream sin;
void build(int idx) {
    string tmp;
    sin >> tmp;
    if(tmp[0] > '9' || tmp[0] < '0' &&) {
        Nd[idx].num = tmp[0];
        Nd[idx].flag = 0;
        size++;
        Nd[idx].l = size;
        build(size);
        size++;
        Nd[idx].r = size;
        build(size);
    } else {
        stringstream nin;
        nin << tmp;
        int v;
        nin >> v;
        Nd[idx].num = v;
        Nd[idx].flag = 1;
    }
}
void travel(int idx) {
    if(!Nd[idx].flag) {
        if(!Nd[Nd[idx].l].flag)
            printf("(");
        travel(Nd[idx].l);
        if(!Nd[Nd[idx].l].flag)
            printf(")");
    if(Nd[idx].num == '+') {
        printf("+");
    } else
    if(Nd[idx].num == '*') {
        printf("*");
    } else
    if(Nd[idx].num == '/') {
        printf("/");
    } else {
        printf("-");
    }
        if(!Nd[Nd[idx].r].flag)
        printf("(");
        travel(Nd[idx].r);
        if(!Nd[Nd[idx].r].flag)
            printf(")");
    } else {
        printf("%d", Nd[idx].num);
    }
}
double calu(int idx) {
    if(Nd[idx].flag)
        return Nd[idx].num;
    if(Nd[idx].num == '+') {
        return calu(Nd[idx].l)+calu(Nd[idx].r);
    } else
    if(Nd[idx].num == '*') {
        return calu(Nd[idx].l)*calu(Nd[idx].r);
    } else
    if(Nd[idx].num == '/') {
        return calu(Nd[idx].l)/calu(Nd[idx].r);
    } else {
        return calu(Nd[idx].l)-calu(Nd[idx].r);
    }
}
int main() {
    int t;
    scanf("%d", &t);
    getchar();
    string line;
    while(t--) {
        getline(cin, line);
        memset(Nd, 0, sizeof(Nd));
        sin.clear();
        sin << line;
        size = 1;
        build(1);
        travel(1);
        printf("=%.2lf\n", calu(1));
    }
    return 0;
}

第五題 這次最難的題目, 樹形 DP

兩次 dfs
1st dfs :
得到由下而上的最大高度 (要記錄第一高 第二高),
意即 得到每個節點的 subtree 的高度
2nd dfs :
將父節點高度轉過來, 這時要注意, 如果第一高是從這個節點接上去的, 那麼就抓第二高+1

#include <stdio.h>
#include <algorithm>
#include <vector>
#define oo 0xfffffff
using namespace std;
vector<int> edge[95005];
int dp_down[95005][2], dp_up[95005];
int used[95005];
void dfs(int nd) {
    for(vector<int>::iterator i = edge[nd].begin(); i != edge[nd].end(); i++) {
        if(used[*i] == 0) {
            used[*i] = 1;
            dfs(*i);
            if(dp_down[*i][0]+1 > dp_down[nd][1])
                dp_down[nd][1] = dp_down[*i][0]+1;
            if(dp_down[nd][1] > dp_down[nd][0])
                swap(dp_down[nd][0], dp_down[nd][1]);
        }
    }
}
void dfs2(int nd, int v) {
    dp_up[nd] = v;
    for(vector<int>::iterator i = edge[nd].begin(); i != edge[nd].end(); i++) {
        if(used[*i] == 0) {
            used[*i] = 1;
            int hv;
            if(dp_down[*i][0]+1 != dp_down[nd][0])
                hv = dp_down[nd][0];
            else
                hv = dp_down[nd][1];
            hv = max(hv, dp_up[nd]);
            dfs2(*i, hv+1);
        }
    }
}
int main() {
    int n, m, i, y;
    while(scanf("%d", &n) == 1) {
        for(i = 1; i <= n; i++) {
            edge[i].clear();
            dp_down[i][0] = 0;
            dp_down[i][1] = 0;
            dp_up[i] = 0;
            used[i] = 0;
        }
        int x, y;
        for(i = 1; i < n; i++) {
            scanf("%d %d", &x, &y);
            x++, y++;
            edge[x].push_back(y);
            edge[y].push_back(x);
        }
        used[1] = 1;
        dfs(1);
        for(i = 1; i <= n; i++) used[i] = 0;
        used[1] = 1;
        dfs2(1, 0);
        int root[95001], best = oo;
        for(i = 1; i <= n; i++) {
            root[i] = max(max(dp_down[i][0], dp_down[i][1]), dp_up[i]);
            best = min(best, root[i]);
        }
        for(i = 1; i <= n; i++)
            if(root[i] == best) {
                printf("%d\n", i-1);
                break;
            }
    }
    return 0;
}