X Distance 搜索或并查集

来源:互联网 发布:真正的绝望是什么知乎 编辑:程序博客网 时间:2024/05/21 22:31

题目大意

给你一个带权无向图, n个节点, m条边, 一个节点到另一个节点的路径的cost等于路径上所有边权值的最大值, 求有多少对节点路径cost等于X

思路

  • 有两种解法, 一种利用搜索
    去掉所有权值大于x的边, 搜索所有联通块, 每个联通块中两两节点之间的cost一定小于x(大于x的边已经去掉了), 所以这个联通块中有a个节点, 那么有a*(a-1)/2对节点cost小于x, 将所有联通图中节点对数加起来就可以得到cost小于等于x的节点对数
    同理去掉大于x-1的边, 就可以求出cost小于x-1的节点对数
    将两个数值相减就可以得到cost等于x的节点对数

  • 另一种解法利用并查集
    将所有边按权值大小从小到达排序, 排序是为了保证当开始处理权值等于x的边时, 所有权值小于x的边已经连接起来了
    记录每个并查集的节点个数, 如果边的权值小于等于x, 并且边的两个节点不在一个并查集里面, 就将它们连起来, 如果这条边的权值刚好等于x, 那么两个并查集中的节点相互连接的cost一定等于x, 那么答案个数增加size(a)*size(b)(两个并查集节点个数乘积

代码


  • 搜索

Language: C++
CPU Time usage: 204 ms
Memory usage: 9020 KB
Source code: 1361 bytes

#include <bits/stdc++.h>using namespace std;const int MAXN = 1E5 + 100;int n, m, x, a, b, c;typedef pair<int, int> P;vector<P> v[MAXN];bool vis[MAXN];long long cnt(int ma){    long long ret = 0;    memset(vis, 0, sizeof(bool)*(n+10));    for(int i=1; i<=n; ++i)    {        if(!vis[i])        {            long long cnt = 1;            vis[i] = 1;            queue<int> que;            que.push(i);            int now, nxt;            while(!que.empty())            {                now = que.front(); que.pop();                for(int i=0; i<(int)v[now].size(); ++i)                {                    nxt = v[now][i].first;                    if(vis[nxt] == 0 && v[now][i].second <= ma)                    {                        ++cnt;                        vis[nxt] = 1;                        que.push(nxt);                    }                }            }            //cout << i << " " << cnt <<endl;            ret += cnt*(cnt-1)/2;        }    }    return ret;}int main(){    ios_base :: sync_with_stdio(0), cin.tie(0), cout.tie(0);    cin >> n >> m >> x;    for(int i=0; i<m; ++i)    {        cin >> a >> b >> c;        v[a].push_back({b, c});        v[b].push_back({a, c});    }    cout << cnt(x) - cnt(x-1) << endl;    return 0;}


  • 并查集

Language: C++
CPU Time usage: 66 ms
Memory usage: 3916 KB
Source code: 1358 bytes
#include <bits/stdc++.h>using namespace std;int a, b, w, n, m, x;const int MAXN = 1E5 + 100;int par[MAXN], rk[MAXN], sz[MAXN];void init(int n){    for(int i=1; i<=n; ++i)    {        par[i] = i;        rk[i] = 0;        sz[i] = 1;    }}int find(int x){    return par[x] == x ? x : x = find(par[x]);}bool same(int x, int y){    return find(x) == find(y);}void unite(int x, int y){    x = find(x);    y = find(y);    if(x == y) return ;    if(rk[x] < rk[y])    {        par[x] = y;        sz[y] += sz[x];    }    else    {        par[y] = x;        sz[x] += sz[y];        if(rk[x] == rk[y]) ++rk[x];    }}struct edge{    int x, y, cost;    bool operator<(const edge & e) const { return cost < e.cost; }};edge es[MAXN*3];int main(){    ios_base :: sync_with_stdio(0), cin.tie(0), cout.tie(0);    cin >> n >> m >> x;    init(n);    for(int i=0; i<m; ++i)        cin >> es[i].x >> es[i].y >> es[i].cost;    sort(es, es+m);    long long ans = 0;    for(int i=0; i<m; ++i)    {        if(es[i].cost>x) break;        if(!same(es[i].x, es[i].y))        {            if(es[i].cost == x) ans += 1ll*sz[find(es[i].x)]*sz[find(es[i].y)];            unite(es[i].x, es[i].y);        }    }    cout << ans << endl;    return 0;}
原创粉丝点击