SDUTACM20级集训队2022春季选拔赛2 补题(Codeforces Gym 102501 A F K)

A-Environment-Friendly Travel

题意:

给定一些交通工具,\(n\)个地点的坐标位置,\(T\)个交通工具的每公里碳排放量,起点和终点的位置,能走的最大距离\(B\),问从起点到终点跑不超过距离\(B\)的情况下的最小碳排放量

思路:

定义\(f(i,dis)\)为到达位置\(i\),行驶了\(dis\)距离的最小碳排放量
比模板的最短路多了一维,二维\(dijkstra\)
把(i,dis)看成一维里的点或者状态,\(f(i,dis)\)就看成一维状态的最小代价
最后,在距离\(<=\)B情况下,取\(min\)即可
注意开\(long long\)

Vie Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
const int N = 2222;
const int M = N * N;
const int inf = 1e18;
typedef pair<int, int> PII;
struct node {
    int x, y;
} pos[N];
struct Point {
    int p;
    int co2;
    int distance;
    bool operator<(const Point &t) const {
        if (co2 != t.co2) return co2 > t.co2;
        return distance > t.distance;
    }
};
int CO[N][N];
int vis[N][N];
int h[M], e[M], ne[M], co[M], w[M], idx;
vector<PII> g[N];
node st, ed;
int B, C[N];
int T, n;
void add_edge(int a, int b, int dis, int val) {
    e[idx] = b, ne[idx] = h[a], co[idx] = val, w[idx] = dis, h[a] = idx++;
}
int cal(node a, node b) {
    return ceil(
        sqrt(1.0 * (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)));
}

void dijkstra() {
    priority_queue<Point> q;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {
            CO[i][j] = inf;
        }
    }
    CO[0][0] = 0;
    q.push({0, 0, 0});
    int cnt = 0;

    while (!q.empty()) {
        auto t = q.top();
        q.pop();
        int now = t.p;

        int nco2 = t.co2;
        int dist = t.distance;
        if (vis[now][dist]) continue;
        vis[now][dist] = 1;
        for (int i = h[now]; ~i; i = ne[i]) {
            int j = e[i];
            int co2 = co[i];
            if (w[i] + dist > B) continue;
            //去掉无用的状态,防止超时
            if (CO[j][w[i] + dist] > CO[now][dist] + co[i]) {
                CO[j][w[i] + dist] = CO[now][dist] + co[i];
                q.push({j, CO[j][w[i] + dist], w[i] + dist});
            }
        }
    }
}
signed main() {
    memset(h, -1, sizeof(h));
    cin >> st.x >> st.y >> ed.x >> ed.y;
    cin >> B >> C[0];
    cin >> T;
    for (int i = 1; i <= T; i++) {
        cin >> C[i];
    }
    cin >> n;
    for (int i = 1, x, y, num; i <= n; i++) {
        cin >> x >> y >> num;
        pos[i] = {x, y};
        for (int j = 1; j <= num; j++) {
            cin >> x >> y;
            g[i].push_back({x, y});
        }
    }
    pos[0] = st;
    pos[n + 1] = ed;

    for (int i = 1; i <= n; i++) {
        int len = g[i].size();
        for (int j = 0; j < len; j++) {
            int sta = g[i][j].first, y = g[i][j].second;
            sta++;
            int dist = cal(pos[i], pos[sta]);
            add_edge(i, sta, dist, dist * C[y]);
            add_edge(sta, i, dist, dist * C[y]);
        }
    }

    for (int i = 1; i <= n; i++) {
        int dist = cal(pos[i], pos[0]);
        add_edge(i, 0, dist, dist * C[0]);
        add_edge(0, i, dist, dist * C[0]);

        dist = cal(pos[i], pos[n + 1]);
        add_edge(i, n + 1, dist, dist * C[0]);
        add_edge(n + 1, i, dist, dist * C[0]);
    }

    int dist = cal(pos[0], pos[n + 1]);
    add_edge(0, n + 1, dist, dist * C[0]);
    add_edge(n + 1, 0, dist, dist * C[0]);
    dijkstra();
    int res = inf;
    for (int i = 0; i <= B; i++) {
        res = min(res, CO[n + 1][i]);
    }

    if (res == inf)
        cout << "-1" << endl;
    else
        cout << res << endl;
}

Icebergs

题意:

求多面形面积的和

思路:

套模板(分割成三角形的思想),求多边形面积,取出的面积记得取绝对值,abs!!!!!!
``

View Code
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int, int> PII;
const int N = 1111;
PII a[N];
int cross(PII a, PII b) { return a.x * b.y - a.y * b.x; }
int area(PII a, PII b, PII c) {
    PII x = {b.x - a.x, b.y - a.y};
    PII y = {c.x - a.x, c.y - a.y};
    return cross(x, y);
}
signed main() {
    int T;
    cin >> T;
    int res = 0;
    while (T--) {
        int n;
        cin >> n;
        for (int i = 0; i < n; i++) {
            int x, y;
            cin >> x >> y;
            a[i] = {x, y};
        }
        int now = 0;
        for (int i = 0; i + 1 < n; i++) {
            now += area(a[0], a[i], a[i + 1]);
        }
        res += abs(now);
    }
    res = res / 2;
    cout << res << endl;
}

Birdwatching

题意:

给定一张有向图,给定一个终点\(v\),问现在有多少个点\(u\),满足所有从\(u\)出发到\(v\)的路径都经过\((u,v)\)

思路:

建立反图,把边反向,对于有边\((u,v)\)的这些点来说,看从终点\(v\)走,到达\(u\)的合法路径数有多少。
但是这种方法对于\(v->u->a->b->u\)这种有环的会误判,会认为\(u\)不合法,因为计数记了\(2\),所以建立反图跑\(BFS\)时,需要建立一个\(fa\)数组,来记录当前点的起点为哪个点,当进入环时,由于已经进入过了,就不会再次重复计数,对于有边\((u,v)\)的这些点,都跑一遍\(BFS\)即可,只要记录的合法路径数\(>1\),说明不符合题意

View Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
vector<int> e[N];
int n, m, s;
vector<int> temp;
vector<int> ans;
int cnt[N];
int fa[N];
void bfs(int u) {
    cnt[u]++;
    queue<int> q;
    q.push(u);
    fa[u] = u;
    while (q.size()) {
        auto t = q.front();
        q.pop();
        for (auto v : e[t]) {
            if (cnt[v] > 1 || v == s || v == u) continue;
            if (fa[v] != u) {
                fa[v] = u;
                q.push(v);
                cnt[v] += cnt[t];
            }
        }
    }
}
int main() {
    cin >> n >> m >> s;
    for (int i = 1, x, y; i <= m; i++) {
        cin >> x >> y;
        if (y == s) {
            temp.push_back(x);
        }
        e[y].push_back(x);
    }

    for (auto i : temp) {
        bfs(i);
    }
    for (auto i : temp) {
        if (cnt[i] == 1) ans.push_back(i);
    }
    sort(ans.begin(), ans.end());
    cout << ans.size() << endl;
    for (auto i : ans) {
        cout << i << endl;
    }
}

posted @ 2022-03-01 11:50  Wraith_G  阅读(49)  评论(0)    收藏  举报
// //