• 教辅的组成


    传送门

    这道题是网络流拆点的基本题,我们来说说网络流拆点。

    首先,为什么要拆点?这道题中描述的是,一本书和一本练习册,一本答案正好组成了一套书册。也就是说其实每本书只能被用一次。如果我们用老套的网络流建图来做这道题的话,会发现一个神奇的事情,就是对于一个书点,可能有不只一条流流过了这个点,也就说明这本书同时被归到了多个书册中!

    但这个是肯定不行的。想一想发现,对于一个点,他其实相当于是两个点之间连了一条容量为无限的边。那么现在我们要限制每个点只能用一次,那么想法自然就来了:把每一本书拆成两个点,在相对应的两个点之间连一条边权为1的边。这样就可以限制每个点都只被用了一次了。

    然后我们愉快的跑Dinic,做完了!

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<iostream>
    #include<cmath>
    #include<set>
    #include<queue>
    #define rep(i,a,n) for(int i = a;i <= n;i++)
    #define per(i,n,a) for(int i = n;i >= a;i--)
    #define enter putchar('
    ')
    
    using namespace std;
    typedef long long ll;
    const int M = 100005;
    const int INF = 1000000009;
    
    int read()
    {
        int ans = 0,op = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
        if(ch == '-') op = -1;
        ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
        ans *= 10;
        ans += ch - '0';
        ch = getchar();
        }
        return ans * op;
    }
    
    struct edge
    {
        int next,to,v,from;
    }e[M<<1];
    
    int n,m,k,p,qq,x,y,S,T,maxflow = 0,head[M],cur[M],dep[M],ecnt = -1;
    queue <int> q;
    
    void add(int x,int y,int z)
    {
        e[++ecnt].to = y;
        e[ecnt].from = x;
        e[ecnt].next = head[x];
        e[ecnt].v = z;
        head[x] = ecnt;
    }
    
    bool bfs(int s,int t)
    {
        memset(dep,-1,sizeof(dep));
        while(!q.empty()) q.pop();
        dep[s] = 0,q.push(s);
        rep(i,S,T) cur[i] = head[i];
        while(!q.empty())
        {
        int k = q.front();q.pop();
        for(int i = head[k];~i;i = e[i].next)
        {
            if(dep[e[i].to] == -1 && e[i].v)
            dep[e[i].to] = dep[k] + 1,q.push(e[i].to);
        }
        }
        return dep[t] != -1;
    }
    
    int dfs(int s,int t,int limit)
    {
        if(s == t || !limit) return limit;
        int flow = 0;
        for(int i = cur[s];~i;i = e[i].next)
        {
        cur[s] = i;
        if(dep[e[i].to] != dep[s] + 1) continue;
        int f = dfs(e[i].to,t,min(limit,e[i].v));
        if(f)
        {
            e[i].v -= f,e[i^1].v += f;
            flow += f,limit -= f;
            if(!limit) break;
        }
        }
        if(!flow) dep[s] = -233333;
        return flow;
    }
    
    int main()
    {
        memset(head,-1,sizeof(head));
        n = read(),m = read(),k = read(),S = 0,T = n * 2 + m + k + 1;
        p = read();
        rep(i,1,p) x = read(),y = read(),add(x+m+k,y,0),add(y,x+m+k,1);
        qq = read();
        rep(i,1,qq) x = read(),y = read(),add(x+m+n+k,y+m,1),add(y+m,x+m+n+k,0);
        rep(i,1,n) add(k+m+i,k+m+n+i,1),add(k+m+n+i,k+m+i,0);
        rep(i,1,m) add(S,i,1),add(i,S,0);
        rep(i,1,k) add(i+m,T,1),add(T,i+m,0);
        //rep(i,0,ecnt) printf("#%d %d %d
    ",e[i].from,e[i].to,e[i].v);
        while(bfs(S,T)) maxflow += dfs(S,T,INF);
        printf("%d
    ",maxflow);
        return 0;
    }
  • 相关阅读:
    Python字典
    Python集合
    Hungray匈牙利算法
    异常捕获模块,throw, try, catch, finally
    《加德纳艺术通史》罗杰克-劳利
    《高效休息法》久贺谷亮
    梯度检验 Gradient check,bias correction, Exponentially Weighted Averages
    方差与偏差,bias vs variance
    大数定理,中心极限定理以及一些常见分布
    聚类-均值漂移
  • 原文地址:https://www.cnblogs.com/captain1/p/9721604.html
Copyright © 2020-2023  润新知