【题解】arc165_c Social Distance on Graph

arc165_c Social Distance on Graph

题意

给定简单无向正权图,\(n\) 个点,\(m\) 条边,给每个点染成红色或者蓝色。

找到一种染色方案,使得所有连接两个同色顶点的简单路径的长度中的最小值最大,求出这个最小值。

题解

知识点:二分,二分图。

比较经典二分设问,那便二分最小值 \(mid\),检查染色方案存在性。

发现题目给出的不仅是正权图,而且求的是所有路径的最小值,那只需要考虑路径为一条边或者两条边即可,即只需要考虑一条顶点同色的边,或者两条顶点异色的边拼在一起。

思考什么时候没有合法染色方案。

当一条边 \((u,v,w)\) 满足 \(w<mid\),则必须使 \(u,v\) 异色。

如果出现一个奇环,环上的边边权都小于 \(mid\),那肯定是没有合法染色方案的,因为颜色只有两种。

如果存在共顶点的满足边权小于 \(mid\) 的两条边的边权之和也小于 \(mid\),那也是不合法的。

检查路径为一条边的过程可以用二分图染色的方式进行,只取边权小于 \(mid\) 边组成新图,做一遍二分图染色。

检查路径为两条边的过程,可以对新图上每个顶点检查从该点出发边权最小的两条边(没有两条就略过),如果边权之和仍然小于 \(mid\),则也是不合法的。

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()

#define N 302507
#define int long long

int n,m,cnt;

struct edge{
    int t,w,i;
};

vector<edge>e[N],g[N];
int col[N],suc;

inline void dfs(int k){
    for(edge x:g[k]){
        if(~col[x.t]){
            if(col[x.t]==col[k]){
                suc=0;
            }
            continue;
        }

        col[x.t]=!col[k];

        dfs(x.t);
    }
}

inline bool chk(int mid){
    rep(i,1,n){
        g[i].clear();
        col[i]=-1;
    }

    rep(i,1,n){
        for(edge x:e[i]){
            if(x.w>=mid){
                continue;
            }

            g[i].pb(x);
        }
    }

    rep(i,1,n){
        if(sz(g[i])<2){
            continue;
        }

        sort(all(g[i]),[](edge x,edge y){
            return x.w<y.w;
        });

        if(g[i][0].w+g[i][1].w<mid){
            return 0;
        }
    }

    suc=1;

    rep(i,1,n){
        if(~col[i]){
            continue;
        }

        col[i]=1;
        dfs(i);
    }

    return suc;
}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    cin>>n>>m;

    rep(i,1,m){
        int u,v,w;
        cin>>u>>v>>w;

        cnt++;
        e[u].pb({v,w,cnt});
        e[v].pb({u,w,cnt});
    }

    int l=1,r=2e9,ans=0;

    while(l<=r){
        int mid=(l+r)>>1;

        if(chk(mid)){
            ans=mid;
            l=mid+1;
        }
        else{
            r=mid-1;
        }
    }

    cout<<ans;

    return 0;
}
posted @ 2025-07-09 12:05  Lucyna_Kushinada  阅读(12)  评论(0)    收藏  举报