4.3 每日一题题解

关押罪犯

涉及知识点:

  • 并查集+贪心 / 二分图+二分

solution:

  • 本题解法不唯一
  • 首先先讲一下并查集+贪心的做法:
  • 题意要求答案最小,所以仇恨值偏大的一对可以视为敌人分开,所以先根据仇恨值sort
  • 根据敌人的敌人就是友人,假如我们将a和b分开,b和c分开,那a和c就相当于在同一个监狱里,b在另外一个监狱里
  • 所以通过并查集,开大一倍数组,用来维护罪犯的补集,即不在同一个监狱的罪犯集合
  • 下面讲一下二分 + 二分图(需要有二分图的前提知识):
  • 很明显答案是要求最大值最小,所以二分答案
  • 然后根据染色法判断二分图是否成立,以及边权的最大值是否小于等于当前的二分答案

并查集+贪心 std:

#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 200005;
int f[maxn];
struct node{
    int u,v,w;
}a[maxn*10];
bool cmp(node p1,node p2){
    return p1.w > p2.w;
}
int find(int x){
    return f[x] == x ? f[x] : f[x] = find(f[x]);
}
void unite(int x,int y){
    x = find(x),y = find(y);
    if(x != y)
        f[x] = y;
}
int main()
{
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=2*n;i++)f[i] = i;
    for(int i=1;i<=m;i++)cin>>a[i].u>>a[i].v>>a[i].w;
    sort(a+1,a+1+m,cmp);
    for(int i=1;i<=m;i++)
    {
        int x = a[i].u;
        int y = a[i].v;
        x = find(x),y = find(y);
        if(x == y){
            cout<<a[i].w<<endl;
            return 0;
        }
        f[x] = find(n + a[i].v);
        f[y] = find(n + a[i].u);
    }
    cout<<"0"<<endl;
    return 0;
}

二分 + 二分图 std(感谢清楚姐的小迷弟贡献的代码):

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
 
using namespace std;
 
const int N = 20010, M = 200010;
 
int n, m;
int h[N], e[M], w[M], ne[M], idx;
int color[N];
 
void add(int a, int b, int c)
{
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;
}
 
bool dfs(int u, int c, int mid)
{
    color[u] = c;
    for (int i = h[u]; ~i; i = ne[i])
    {
        int j = e[i];
        if (w[i] <= mid) continue;
        if (color[j])
        {
            if (color[j] == c) return false;
        }
        else if (!dfs(j, 3 - c, mid)) return false;
    }
 
    return true;
}
 
bool check(int mid)
{
    memset(color, 0, sizeof color);
    for (int i = 1; i <= n; i ++ )
        if (!color[i])
            if (!dfs(i, 1, mid))
                return false;
    return true;
}
 
int main()
{
    scanf("%d%d", &n, &m);
    memset(h, -1, sizeof h);
 
    while (m -- )
    {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        add(a, b, c), add(b, a, c);
    }
 
    int l = 0, r = 1e9;
    while (l < r)
    {
        int mid = l + r >> 1;
        if (check(mid)) r = mid;
        else l = mid + 1;
    }
 
    printf("%d\n", r);
 
    return 0;
}
posted @ 2020-04-03 10:04  QFNU-ACM  阅读(157)  评论(0)    收藏  举报