版本1:并查集 - 俗话说敌人的敌人就是朋友
遍历所有的冲突,如果冲突双方不在同一个监狱里(不在同一个监狱的条件:其集合祖先fa[i]不是同一个),将一方归入另一方敌人所在的监狱,利用并查集,将同一监狱的人合并,
至于怎么遍历,贪啊!
版本2:二分+二分图
最小的最大冲突影响力 - - 首先想到二分单调答案
两个监狱 - - 二分图,判断是否符合条件,为了防止MLE,二分图采用bfs形式
并查集
#include
using namespace std;
const int N=1e6+10;
int n,m;
struct edge{
int u,v,w;
void init(){
cin>>u>>v>>w;
}
}e[N];
bool cmp(edge x,edge y){return x.w>y.w;}
int fa[N];//将同盟者归为一类
int find(int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
bool judge(int u,int v){return find(u)==find(v);}
void join(int u,int v){
u=find(u);v=find(v);
fa[u]=v;
}
int enemy[N];//敌人
int main(){
cin>>n>>m;
for (int i = 1; i <= n; ++i) fa[i]=i;
for (int i = 1; i <= m; ++i) e[i].init();
sort(e+1,e+1+m,cmp);//从大到小排列 贪心
for (int i = 1; i <= m; ++i) {
int u=e[i].u;
int v=e[i].v;
if(judge(u,v)){//如果在同一个集合内
return printf("%d", e[i].w),0;
}else{
if(!enemy[u]) enemy[u]=v;
else join(enemy[u],v);//合并敌人
if(!enemy[v]) enemy[v]=u;
else join(enemy[v],u);
}
}
puts("0");//当没有冲突时 输出0
return 0;
}
二分+二分图(bfs)
#include
using namespace std;
const int N=1e6+10;
int n,m;
struct edge{
int next,to,w;
}e[N];
int head[N],tot=0;
int color[N];
void add(int u,int v,int w){
e[++tot].to=v;
e[tot].w=w;
e[tot].next=head[u];
head[u]=tot;
}
bool check(int ans){
queue<int>q;
memset(color, 0, sizeof(color));//每次判断都要清空
for (int i = 1; i <= n; ++i) {
if(!color[i]){
q.push(i);
color[i]=1;
while(q.size()){
int u=q.front();
q.pop();
for (int j = head[u]; j; j=e[j].next) {
if(e[j].w>ans){//冲突影响力值大于答案 说明要分图
int v=e[j].to;
if(!color[v]){//如果没有染过色
color[v]=3-color[u];
q.push(v);
}else if(color[v]==color[u])return false;
}
}
}
}
}
return true;
}
int main(){
int r=0;
cin>>n>>m;
for (int i = 1,u,v,w; i <= m; ++i) {
cin>>u>>v>>w;
add(u,v,w);
add(v,u,w);
r=max(r,w);//二分边界
}
int l=0,mid;
while(l<r){
mid=(l+r)/2;
if(check(mid)){
r=mid;
}else l=mid+1;
}
printf("%d",r);
return 0;
}