Problem A 挑战密室

题目链接:http://nyoj.top/problem/1236

题意:求第一个生成物的分子质量。
思路:字符串模拟,稍微细心一下基本上都能过的。

#include <bits/stdc++.h>
using namespace std;
int i, len;
char str[55];
int Judge() {
    int t, wei, cnt, num, ans = 0;
    while (i < len && str[i] != '+' && str[i] != ')') {
        if (str[i] == '(') {
            i = i + 1;
            cnt = Judge();
            if (isdigit(str[++i])) {
                sscanf(str + i, "%d%n", &num, &wei);
                i += wei;
                cnt *= num;
            }
            ans += cnt;
        }
        cnt = 0;
        if (str[i] == 'N' && str[i + 1] == 'a')
            cnt = 23, i += 2;
        else if (str[i] == 'Z' && str[i + 1] == 'n')
            cnt = 65, i += 2;
        else if (str[i] == 'C' && str[i + 1] == 'a')
            cnt = 40, i += 2;
        else if (str[i] == 'A' && str[i + 1] == 'l')
            cnt = 27, i += 2;
        else if (str[i] == 'C' && str[i + 1] == 'l')
            cnt = 35, i += 2;
        else if (str[i] == 'H')
            cnt = 2, i++;
        else if (str[i] == 'S')
            cnt = 32, i++;
        else if (str[i] == 'O')
            cnt = 16, i++;
        else if (str[i] == 'C')
            cnt = 12, i++;
        else if (str[i] == 'N')
            cnt = 14, i++;
        if (isdigit(str[i])) {
            sscanf(str + i, "%d%n", &num, &wei);
            i += wei;
            cnt *= num;
        }
        ans += cnt;
    }
    return ans;
}
int main() {
    int t, ans;
    scanf("%d", &t);
    while (t--) {
        scanf("%s", str);
        len = strlen(str);
        for (i = 0; str[i] != '='; i++);
        if (isdigit(str[++i])) {
            ans = 0;
            while (isdigit(str[i]))
                ans = ans * 10 + str[i++] - '0';
        }
        else ans = 1;
        ans *= Judge();
        printf("%04d\n", ans);
    }
    return 0;
}

Problem B 最大岛屿

题目链接:http://nyoj.top/problem/1237

题意:1代表陆地,0代表海水,问整个海域的海岛数,以及最大海岛的面积。
思路:简单的深搜,每次找到一个岛,就把这个岛每一个地方都标记上,这样就可以计算出有多少个岛了,找出最大的肯定就简单多了。

#include <bits/stdc++.h>
using namespace std;
int mp[505][505], n, m, p, ans, cnt, max_;
int arr[8][2] = {0, 1, 1, 0, -1, 0, 0, -1, 1, 1, 1, -1, -1, 1, -1, -1};
void DFS(int x, int y) {
    cnt++;
    int tx, ty;
    mp[x][y] = 0;
    for (int i = 0; i < 8; i++) {
        tx = x + arr[i][0];
        ty = y + arr[i][1];
        if (tx >= 0 && tx < n && ty >= 0 && ty < m && mp[tx][ty])
            DFS(tx, ty);
    }
}
int main() {
    ans = max_ = 0;
    scanf("%d%d%d", &n, &m, &p);
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            scanf("%1d", &mp[i][j]);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            if (mp[i][j]) {
                ans++;
                cnt = 0;
                DFS(i, j);
                max_ = max(cnt, max_);
            }
        }
    }
    printf("%d %d\n", ans, max_ * p);
    return 0;
}

Problem C 最少换乘

题目链接:http://nyoj.top/problem/1238

题意:给你一些BUS线路上的所有站号,求从住处到景点,中间换车的次数最少。
思路:有的题解是用最短路写的,但是我认为等权值的用广搜更快一点,就写了一个广搜的代码。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 505;
struct edge {
    int s, t;
}p, q;
char str[MAXN << 1];
int mp[MAXN][MAXN], vis[MAXN], ans[MAXN], n;
int BFS(int s) {
    queue <edge> Q;
    Q.push((edge){1, 0});
    vis[s] = 1;
    while (!Q.empty()) {
        p = Q.front();
        Q.pop();
        for (int i = 1; i <= n; i++) {
            if (!vis[i] && mp[p.s][i]) {
                vis[i] = 1;
                q.s = i;
                q.t = p.t + 1;
                if (q.s == n)
                    return p.t;
                Q.push(q);
            }
        }
    }
    return -1;
}
int main() {
    int t, m, k, len;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d", &m, &n);
        memset(mp, 0, sizeof(mp));
        memset(vis, 0, sizeof(vis));
        while (m--) {
            k = 0;
            getchar();
            scanf("%[^\n]", str);
            len = strlen(str);
            memset(ans, 0, sizeof(ans));
            for (int i = 0; i < len; i++) {
                if (isdigit(str[i]))
                    ans[k] = ans[k] * 10 + str[i] - '0';
                else k++;
            }
            k++;
            for (int i = 0; i < k; i++)
                for (int j = i + 1; j < k; j++)
                    mp[ans[i]][ans[j]] = 1;
        }
        int cnt = BFS(1);
        if (cnt != -1)
            printf("%d\n", cnt);
        else printf("NO\n");
    }
    return 0;
}

Problem D 引水工程

题目链接:http://nyoj.top/problem/1239

题意:给出自建水库的费用以及从第i个区域到第j个区域引水的费用,求使所有地区都用上水的最小费用。
思路:裸最小生成树,只不过要判断一下,是引水费用小还是自建水库费用小。

#include <bits/stdc++.h>
using namespace std;
const int N = 305;
const int inf = 0x3f3f3f3f;
int minn, n, mp[N][N], vis[N], dis[N], w[N];
int prim(int s) {
    int k, sum = w[s];
    for (int i = 0; i < n; i++) {
        vis[i] = 0;
        dis[i] = min(mp[s][i], w[i]);
    }
    vis[s] = 1;
    for (int i = 0; i < n - 1; i++) {
        minn = inf;
        for (int j = 0; j < n; j++)
            if (!vis[j] && dis[j] < minn)
                minn = dis[k = j];
        vis[k] = 1;
        sum += minn;
        for (int j = 0; j < n; j++)
            if (!vis[j] && dis[j] > mp[k][j])
                dis[j] = mp[k][j];
    }
    return sum;
}
int main() {
    int s, t;
    scanf("%d", &t);
    while (t--) {
        s = 0;
        scanf("%d", &n);
        memset(vis, 0, sizeof(vis));
        for (int i = 0; i < n; i++) {
            scanf("%d", &w[i]);
            if (w[i] < w[s])
                s = i;
        }
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
                scanf("%d", &mp[i][j]);
        printf("%d\n", prim(s));
    }
    return 0;
}

Problem F Distribution

题目链接:http://nyoj.top/problem/1241

题意:给出N个宝藏坐标,然后给出M个画线的交点坐标,输出每次画线后区域(I+III)-(II+IV)的结果。
思路:直接判断就行了。

#include <bits/stdc++.h>
using namespace std;
struct edge {
    int x, y;
}e[105];
int main() {
    int n, m, x, y;
    scanf("%d%d", &n, &m);
    for (int i = 0; i < n; i++)
        scanf("%d%d", &e[i].x, &e[i].y);
    while (m--) {
        int a = 0, b = 0;
        scanf("%d%d", &x, &y);
        for (int i = 0; i < n; i++) {
            if (e[i].x > x && e[i].y > y || e[i].x < x && e[i].y < y)
                a++;
            else b++;
        }
        printf("%d\n", a - b);
    }
    return 0;
}

Problem G Interference Signal

题目链接:http://nyoj.top/problem/1242

题意:求连续序列大于等于k个的最大平均值。
思路:数据比较水,直接暴力就完事了,注意输出的时候不要四舍五入。

#include <bits/stdc++.h>
using namespace std;
int main() {
    int t, n, m, a[2005];
    scanf("%d", &t);
    while (t--) {
        double sum, max_ = 0;
        scanf("%d%d", &n, &m);
        for (int i = 0; i < n; i++)
            scanf("%d", &a[i]);
        for (int i = 0; i <= n - m; i++) {
            for (int j = m; j <= n - i; j++) {
                sum = 0;
                for (int k = i; k < i + j; k++)
                    sum += a[k];
                max_ = max(max_, sum / j);
            }
        }
        printf("%d\n", (int)(max_ * 1000));
    }
    return 0;
}