zoukankan      html  css  js  c++  java
  • [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;
    }
    
  • 相关阅读:
    Windows下如何检测用户修改了系统时间并且把系统时间改回来
    洛谷 1220 关路灯
    洛谷 2279 [HNOI2003]消防局的设立
    洛谷 1498 南蛮图腾
    bzoj 1036 [ZJOI2008]树的统计Count 树链剖分模板
    codevs 1021 玛丽卡 SPFA
    codevs 1077 多源最短路 flyod
    Vijos P1133 装箱问题 01背包
    codevs 1069 关押罪犯 并查集
    codevs 1073 家族 并查集
  • 原文地址:https://www.cnblogs.com/asuldb/p/10492722.html
Copyright © 2011-2022 走看看