第八次CCF计算机软件能力认证

1、最大波动

ACwing 3232

#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1010;

int n, last, res;

int main() {
    cin >> n >> last;
    for (int i = 1; i < n; i ++ ) {
        int x; cin >> x;
        res = max(res, abs(x - last));
        last = x;
    }
    cout << res << endl;
    return 0;
}

2、火车购票

ACwing 3233

#include <iostream>
#include <algorithm>

using namespace std;

int n, p;
int cnt[20], per[20][5];

int main() {
    cin >> n;
    while (n--) {
        cin >> p;
        bool flag = false;
        for (int i = 0; i < 20; i++) {
            if (5 - cnt[i] >= p) {
                cnt[i] += p, flag = true;
                for (int j = 0; j < 5; j++) {
                    if (!per[i][j]) {
                        per[i][j] = 1;
                        cout << i * 5 + j + 1 << " ";
                        p -- ;
                    }
                    if (!p) break;
                }
                break;
            }
        }
        if (!flag)
            for (int i = 0; i < 20; i++) {
                for (int j = 0; j < 5; j++) {
                    if (!per[i][j]) {
                        per[i][j] = 1;
                        cout << i * 5 + j + 1 << " ";
                        cnt[i]++;
                        p--;
                    }
                    if (!p) break;
                }
                if (!p) break;
            }
        cout << endl;
    }
    return 0;
}

3、炉石传说

ACwing 3234

数组 p [ 2 ] [ 10 ] p[2][10] p[2][10]:第一维 0 0 0 表示前者, 1 1 1 表示后者;第二维 0 0 0 表示英雄生命值, 1 ∼ 7 1 \sim 7 17 分别表示随从的生命值.

#include <iostream>
#include <algorithm>
using namespace std;

struct Role {
    int a, h; // 攻击力、生命值
} p[2][10];

void remove(int k, int pos) {
    for (int i = pos; i <= 7; i++)
        p[k][i] = p[k][i + 1];
}

int main() {
    int n; cin >> n;
    p[0][0].h = p[1][0].h = 30;
    int k = 0;
    while (n--) {
        string op; cin >> op;
        if (op == "end") k ^= 1; // 交换回合
        else if (op == "summon") {
            int pos, a, h; cin >> pos >> a >> h;
            for (int i = 7; i > pos; i--) p[k][i] = p[k][i - 1];
            p[k][pos] = {a, h};
        } else {
            int a, d; cin >> a >> d;
            p[k][a].h -= p[!k][d].a;
            p[!k][d].h -= p[k][a].a;
            if (a && p[k][a].h <= 0) remove(k, a);
            if (d && p[!k][d].h <= 0) remove(!k, d);
        }
    }
    if (p[0][0].h <= 0) puts("-1");
    else if (p[1][0].h <= 0) puts("1");
    else puts("0");
    for (int k = 0; k < 2; k++) {
        cout << p[k][0].h << endl;
        int s = 0;
        for (int i = 1; i <= 7; i++)
            if (p[k][i].h > 0) s++;
        cout << s << ' ';
        for (int i = 1; i <= s; i++)
            cout << p[k][i].h << ' ';
        cout << endl;
    }
    return 0;
}

4、交通规划 (最短路树)

ACwing 3235

首先应该明确,最终选择出来的权值之和最小的边构成的一定是一棵树而不是环。如果存在一个环,环上存在从 A → C A \rightarrow C AC B → C B \rightarrow C BC 两条最短路径,并且从 B → C B \rightarrow C BC 的路径权值大于 0 0 0 。那么现在将 B → C B \rightarrow C BC 之间的路径删除后,依然是满足最短路径的,所以最终选择出来的一定是一棵树。
在这里插入图片描述

但是这个题目并不是求解最小生成树,比如存在如下的图, 如果求解最小生成树后,从 A → C A \rightarrow C AC 的最小距离就从 3 3 3 变成了 4 4 4
在这里插入图片描述
这个题目是求解最短路树。求解方法:

假设有点 a 、 b a、b ab 到根结点 1 1 1 的距离分别为 d i s t [ a ] 、 d i s t [ b ] dist[a]、dist[b] dist[a]dist[b],且 a 、 b a、b ab 之间边的权值为 w a b w_{ab} wab,如果要选择 a b ab ab 这条边,就必须要满足式子 d i s t [ a ] = d i s t [ b ] + w a b dist[a] = dist[b] + w_{ab} dist[a]=dist[b]+wab因此可以先预处理对于每一个点有哪些边可以选择,然后由题目所有边的权值 1 ≤ c ≤ 1000 1\le c \le1000 1c1000,可以知道所有满足上式的边一定也满足 d i s t [ a ] > d i s t [ b ] dist[a] > dist[b] dist[a]>dist[b],因此可见最佳方案会是一个拓扑图。

如果采用拓扑顺序来考虑所有的点,当枚举到第 i i i 个点的时候,用 f [ i ] f[i] f[i] 表示选择前 i i i 点的最小权值之和,并且假设在前 i − 1 i - 1 i1 个点中存在指向第 i i i 个结点的边: j → i 、 k → i 、 t → i j \rightarrow i、k \rightarrow i、t \rightarrow i jikiti,那么就有 f ( i ) = f ( i − 1 ) + m i n { w j i , w k i , w t i } f(i) = f(i-1) + min\{ w_{ji},w_{ki},w_{ti} \} f(i)=f(i1)+min{wji,wki,wti}

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;

const int N = 10010, M = 200010, INF = 0x3f3f3f3f;

int n, m;
int h[N], e[M], w[M], ne[M], idx;
int dist[N], q[N];
bool st[N];

void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}

void spfa() {
    memset(dist, 0x3f, sizeof dist); dist[1] = 0;
    int hh = 0, tt = 1; q[0] = 1;
    while (hh != tt) {
        int t = q[hh++];
        if (hh == N) hh = 0;
        st[t] = false;
        for (int i = h[t]; ~i; i = ne[i]) {
            int j = e[i];
            if (dist[j] > dist[t] + w[i]) {
                dist[j] = dist[t] + w[i];
                if (!st[j]) {
                    q[tt++] = j;
                    if (tt == N) tt = 0;
                    st[j] = true;
                }
            }
        }
    }
}

int main() {
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
    while (m--) {
        int a, b, c; scanf("%d%d%d", &a, &b, &c);
        add(a, b, c), add(b, a, c);
    }
    spfa();
    int res = 0;
    for (int a = 2; a <= n; a++) {
        int minw = INF;
        for (int j = h[a]; ~j; j = ne[j]) {
            int b = e[j];
            if (dist[a] == dist[b] + w[j])
                minw = min(minw, w[j]);
        }
        res += minw;
    }
    printf("%d\n", res);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值