首页 > 其他分享 >1月7日

1月7日

时间:2025-01-07 20:11:34浏览次数:1  
标签: return int fa low ans find

上午思维题训练

https://codeforces.com/contest/2026/problem/C

https://codeforces.com/contest/2026/problem/B

https://codeforces.com/contest/2023/problem/A

https://codeforces.com/contest/2034/problem/D

下午

https://vjudge.net/problem/HDU-4612

题意:有一个无向图,加一条无向边使得这个图的割边最小。

思路:通过eDcc缩点,缩成一棵树,然后求树的直径,答案就是割边-树的直径

思路AC,代码没有AC,一直MLE,日后再改。

#include <bits/stdc++.h>
//#define int long long
#define endl '\n'
using namespace std;
//typedef unsigned __int128 LL;
const int N=2e4+10,M=1e6+10,inf=1e16,mod=1e8;
int n,m;
struct edge{
    int v,last;
}e[M];
int h[N],idx;//0开始
vector<int> fir;
void add(int u,int v) {
    fir.push_back(u);
    e[idx].v=v;
    e[idx].last=h[u];
    h[u] = idx++;
}
int dfn[N],low[N],tot;
stack<int> stk;
int dcc[N],cnt;//dcc记录边双连通分量
int bri[M];//bri[i]记录割边
void tarjan(int x,int edg) {
    dfn[x] = low[x] = ++tot;
    stk.push(x);
    for (int i = h[x]; ~i; i = e[i].last) {
        int y = e[i].v;
        if (!dfn[y]) {
            tarjan(y, i);
            low[x] = min(low[y], low[x]);
            if (low[y] > dfn[x]) {//割边
                bri[i] = 1;
                bri[i ^ 1] = 1;
            }
        } else if (i != (edg ^ 1)) {
            low[x] = min(dfn[y], low[x]);
        }
    }
    //离,判边双连通分量
    if (dfn[x] == low[x]) {
        ++cnt;
        while (1) {
            int y = stk.top();
            stk.pop();
            dcc[y] = cnt;
            if (x == y) break;
        }
    }
}
vector<int> ne[N];
int ans=0;
int dfs(int u,int f){
    int d1=0,d2=0;
    for(auto v:ne[u]){
        if(v==f) continue;
        int d=dfs(v,u)+1;
        if(d>d1) d2=d1,d1=d;
        else if(d>d2) d2=d;
    }
    ans=max(ans,d1+d2);
    return d1;
}
void solve() {
    while(cin>>n>>m){
        if(n==0&&m==0) break;
        idx=tot=cnt=ans=0;
        for(int i=0;i<=n;i++) {
            dfn[i]=low[i]=0;
            h[i]=-1;
            dcc[i]=0;
            ne[i].clear();
        }
        while(!stk.empty()) stk.pop();
        for(int i=0;i<=m;i++){
            e[i].v=-1,e[i].last=-1;
            bri[i]=0;
        }
        for(int i=1;i<=m;i++){
            int u,v;
            cin>>u>>v;
            add(u,v);
            add(v,u);
        }
        for(int i=1;i<=n;i++){
            if(!dfn[i]) tarjan(i,-1);
        }
        for(int i=0;i<idx;i++){
            if(bri[i]){
                ne[dcc[fir[i]]].push_back(dcc[e[i].v]);
            }
        }
        dfs(1,-1);
        cout<<cnt-1-ans<<endl;
    }
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
//    int _;
//    cin >> _;
//    while (_--)
        solve();
    return 0;
}

畅通工程再续 - HDU 1875 - Virtual Judge

这题比较典,数据较小,所以暴力建边,然后并查集求最小生成树。

#include <bits/stdc++.h>
//#define int long long
#define endl '\n'
using namespace std;
//typedef unsigned __int128 LL;
const int N=105,M=1e6+10,inf=1e16,mod=1e8;
double dis[105][105];
int fa[N];
struct node {
    double x, y;
};
double f(node a,node b) {
    return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
struct node1 {
    int u, v;
    double w;
}e[M];
int find(int x) {
    if (fa[x] == x) return x;
    return fa[x] = find(fa[x]);
}

void solve() {
    int n;
    cin >> n;
    vector<node> v;
    v.push_back({0, 0});
    for (int i = 1; i <= n; i++) {
        double x, y;
        cin >> x >> y;
        v.push_back({x, y});
    }
    int cnt = 0;
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j < i; j++) {
            dis[j][i] = f(v[j], v[i]);
            ++cnt;
            e[cnt].u = j, e[cnt].v = i, e[cnt].w = dis[j][i];
        }
    }
    auto cmp = [&](node1 a, node1 b) {
        return a.w < b.w;
    };
    double ans = 0;
    for (int i = 1; i <= n; i++) fa[i] = i;
    sort(e + 1, e + cnt + 1, cmp);
    auto kruscal = [&]() {
        int num = 0;
        for (int i = 1; i <= cnt; i++) {
            if (e[i].w > 1000) break;
            if (e[i].w < 10) continue;
            int x = find(e[i].u);
            int y = find(e[i].v);
            if (x != y) {
                fa[x] = y;
                ans += e[i].w;
                num++;
            }
        }
        return num == n - 1;
    };
    if (kruscal()) printf("%.1lf\n", ans * 100);
    else cout << "oh!" << endl;
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    int _;
    cin >> _;
    while (_--)
        solve();
    return 0;
}

[P1967 NOIP2013 提高组] 货车运输 - 洛谷 | 计算机科学教育新生态

题意:有一个带权无向图,现在询问图上任意两点的所有路径中最大的边权

思路:要求最大边权,所以,可想而知,图上有些小边权是用不上的,所以要去掉一些边,首先建最大生成树,

然后在最大生成树上求任意两点的路径最大边权,倍增求LCA的时候,可以求出树上俩点的路径,是在图上向上跳,递推而来的,同样,所以求最大边权可以求LCA得来。

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
//typedef unsigned __int128 LL;
const int N=3e4+10,M=5e4+10,inf=1e16,mod=1e8;
int fa[N],dfn[N],dep[N];
int Fa[N][25],dis[N][25],tot;
int n,m;
struct edge {
    int u, v, w;

    bool operator<(const edge &t) const {
        return w > t.w;
    }
}e[M];
struct node {
    int v, w;
};
vector<node> ne[N];
int find(int x) {
    if (x == fa[x]) return x;
    return fa[x] = find(fa[x]);
}

void kruscal() {
    for (int i = 1; i <= m; i++) {
        int x = find(e[i].u), y = find(e[i].v);
        if (x != y) {
            fa[x] = y;
            ne[e[i].u].push_back({e[i].v, e[i].w});
            ne[e[i].v].push_back({e[i].u, e[i].w});
        }
    }
}

void dfs(int now,int f) {
    dep[now] = dep[f] + 1;
    dfn[now] = ++tot;
    Fa[now][0] = f;
    for (int i = 0; i <= 21; i++) {
        Fa[now][i + 1] = Fa[Fa[now][i]][i];
        if (dfn[Fa[now][i + 1]]) dis[now][i + 1] = min(dis[now][i], dis[Fa[now][i]][i]);
    }
    for (auto k: ne[now]) {
        int v = k.v, w = k.w;
        if (v != f) {
            dis[v][0] = w;
            dfs(v, now);
        }
    }
}
int lca(int x,int y) {
    int ans = 1e16;
    if (dep[x] < dep[y]) swap(x, y);
    for (int i = 22; i >= 0; i--) {
        if (dep[Fa[x][i]] >= dep[y]) ans = min(ans, dis[x][i]), x = Fa[x][i];
    }
    if (x == y) return ans;
    for (int i = 22; i >= 0; i--) {
        if (Fa[x][i] != Fa[y][i]) {
            ans = min(ans, min(dis[x][i], dis[y][i]));
            x = Fa[x][i], y = Fa[y][i];
        }
    }
    ans = min(ans, min(dis[x][0], dis[y][0]));
    return ans;
}
void solve() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        cin >> e[i].u >> e[i].v >> e[i].w;
    }
    for (int i = 1; i <= n; i++) fa[i] = i;
    sort(e + 1, e + m + 1);
    kruscal();
    for (int i = 1; i <= n; i++) {
        for (int j = 0; j <= 22; j++) dis[i][j] = 1e16;
    }
    for (int i = 1; i <= n; i++) {
        if (!dfn[i]) dis[i][0] = 1e16, dfs(i, 0);
    }
    int q;
    cin >> q;
    while (q--) {
        int x, y;
        cin >> x >> y;
        if (find(x) != find(y)) {
            cout << -1 << endl;
            continue;
        }
        cout << lca(x, y) << endl;
    }
}

signed main() {
    ios_base::sync_with_stdio(0), cin.tie(0), cout.tie(0);
//    int _;
//    cin >> _;
//    while (_--)
        solve();
    return 0;
}

标签:,return,int,fa,low,ans,find
From: https://www.cnblogs.com/Cakefish/p/18658292

相关文章