[TJOI2018]智力竞赛

题目

发现我们需要最大化最小值,基本是二分了

那么我们二分出来一个值我们将小于等于这个值的都删去,现在的问题变成了如何用(n+1)条路径覆盖这张图

这不最小路径覆盖吗

于是我就忘了最小路径覆盖怎么搞了

在慎老师的教育下我终于知道了最小路径覆盖应该先将每个点拆成两个点,放在二分图的左右两边,对于原图的一条边((x,y)),我们就连((x,y')),之后最小路径覆盖就等于总点数减最大匹配

其实挺好理解的,先考虑一条匹配边都没有的情况,最小路径覆盖就是总点数,每加入一条匹配边就会让我们少用一次覆盖

代码

#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define LL long long
#define inf 999999999
#define re register
#define maxn 1005
inline int read() {
    int x=0;char c=getchar();while(c<'0'||c>'9') c=getchar();
    while(c>='0'&&c<='9') x=(x<<3)+(x<<1)+c-48,c=getchar();return x;
}
struct E{int v,nxt,f;}e[maxn*maxn];
int n,num,m,S,T;
int head[maxn],cur[maxn],d[maxn],val[maxn],c[maxn];
std::vector<int> v[maxn];
inline void add(int x,int y,int w) {e[++num].v=y;e[num].nxt=head[x];head[x]=num;e[num].f=w;}
inline void C(int x,int y,int w) {add(x,y,w),add(y,x,0);}
inline int BFS() {
    std::queue<int> q;
    for(re int i=S;i<=T;i++) cur[i]=head[i],d[i]=0;
    d[S]=1,q.push(S);
    while(!q.empty()) {
        int k=q.front();q.pop();
        for(re int i=head[k];i;i=e[i].nxt)
        if(e[i].f&&!d[e[i].v]) d[e[i].v]=d[k]+1,q.push(e[i].v);
    }
    return d[T];
}
int dfs(int x,int now) {
    if(x==T||!now) return now;
    int flow=0,ff;
    for(re int& i=cur[x];i;i=e[i].nxt) 
    if(d[e[i].v]==d[x]+1) {
        ff=dfs(e[i].v,min(e[i].f,now));
        if(ff<=0) continue;
        now-=ff,flow+=ff,e[i].f-=ff,e[i^1].f+=ff;
        if(!now) break;
    }
    return flow;
}
inline int check(int x) {
    int tot=0;
    memset(head,0,sizeof(head));num=1;
    for(re int i=1;i<=m;i++) {
        if(val[i]>=x) continue;
        C(S,i,1);C(i+m,T,1);tot++;
        for(re unsigned int j=0;j<v[i].size();j++) 
        if(val[v[i][j]]<x) C(i,v[i][j]+m,1);
    }
    int ans=tot;
    while(BFS()) ans-=dfs(S,inf);
    return ans<=n;
}
int main() {
    n=read()+1,m=read();
    for(re int i=1;i<=m;i++) {
        val[i]=read(),num=read();
        for(re int j=1;j<=num;j++) v[i].push_back(read());
    }
    S=0,T=m+m+1;
    if(check(inf)) {puts("AK");return 0;}
    for(re int i=1;i<=m;i++) c[i]=val[i];
    std::sort(c+1,c+m+1);
    int l=1,r=m,ans=0;
    while(l<=r) {
        int mid=l+r>>1;
        if(check(c[mid])) l=mid+1,ans=mid;else r=mid-1;
    }
    printf("%d
",c[ans]);
    return 0;
}
原文地址:https://www.cnblogs.com/asuldb/p/10492722.html