【洛谷P4589】[TJOI2018]智力竞赛(二分+最小链覆盖)

洛谷

题意:
给出一个\(DAG\),现在要选出\(n+1\)条可相交的链来覆盖,最终使得未被覆盖的点集中,权值最小的点的权值最大。

思路:

  • 显然最终的答案具有单调性,故直接二分答案来判断;
  • 直接将小于二分权值的点加入图中,求出最小链覆盖即可。

这个题貌似有点卡常。。二分上界设为INF直接T飞了。。

/*
 * Author:  heyuhhh
 * Created Time:  2019/11/6 10:20:13
 */
#include <bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
#define Local
#ifdef Local
  #define dbg(args...) do { cout << #args << " -> "; err(args); } while (0)
  void err() { std::cout << '\n'; }
  template<typename T, typename...Args>
  void err(T a, Args...args) { std::cout << a << ' '; err(args...); }
#else
  #define dbg(...)
#endif
void pt() {std::cout << '\n'; }
template<typename T, typename...Args>
void pt(T a, Args...args) {std::cout << a << ' '; pt(args...); }
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 500 + 5;

int n, m, T;
int v[N];
int g[N][N];
int match[N], vis[N];
int tmp[N], tot;

int dfs(int u) {
    for(int i = 1; i <= tot; i++) {
        if(vis[i] != T && g[tmp[u]][tmp[i]]) {
            vis[i] = T;
            if(match[i] == -1 || dfs(match[i])) {
                match[i] = u;
                return 1;
            }
        }
    }   
    return 0;
}

bool chk(int x) {
    tot = 0;
    for(int i = 1; i <= m; i++) if(v[i] < x) tmp[++tot] = i;
    int ans = tot;
    for(int i = 1; i <= tot; i++) match[i] = -1;
    for(int i = 1; i <= tot; i++) {
        ++T; ans -= dfs(i);
    }
    return ans <= n + 1;
}

void run(){
    cin >> n >> m;
    int Max = 0;
    for(int i = 1; i <= m; i++) {
        cin >> v[i];
        Max = max(Max, v[i]);
        int k; cin >> k;
        for(int j = 1; j <= k; j++) {
            int x; cin >> x;
            g[i][x] = 1;
        }
    }
    for(int k = 1; k <= m; k++)
        for(int i = 1; i <= m; i++)
            for(int j = 1; j <= m; j++) 
                g[i][j] |= (g[i][k] & g[k][j]);
    if(chk(INF)) {
        cout << "AK" << '\n';
        return;
    }
    int l = 0, r = Max + 1, mid;
    while(l < r) {
        mid = (l + r) >> 1;
        if(chk(mid)) l = mid + 1;
        else r = mid;
    }
    cout << l - 1 << '\n';
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/heyuhhh/p/11809873.html
今日推荐