【题解】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;
}

浙公网安备 33010602011771号