zoukankan      html  css  js  c++  java
  • POJ 3281_Dining

    题意:

    FJ准备了F种食物和D种饮料,每头牛都有喜欢的食物和饮料,并且每头牛都只能分配一种食物和饮料。问如何分配使得同时得到喜欢的食物和饮料的牛数量最多。

    分析:

    首先想到将牛与其对应的食物和饮料匹配起来,即在食物、饮料与牛之间连一条边,再在s和所有食物之间、t和所有饮料之间连一条边。这样每一条路径都对应着食物饮料和牛之间的匹配方案。那么如何避免一头牛被分配多组匹配呢?就将一头牛拆成两个结点,并用一条容量为1的边连接起来,这样求出构成的图中的最大流,即得解。这里使用的是Dinic算法。

    代码:

    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<queue>
    using namespace std;
    struct edge{int to, cap, rev;};
    const int maxn = 105, maxm = 2000055, INF = 0x3fffffff;
    int d[maxm], iter[maxm];
    int s, t;
    vector<edge>G[maxm];
    int dr[maxn][maxn], f[maxn][maxn];
    void add_edge(int from, int to, int cap)
    {
        G[from].push_back((edge){to, cap, G[to].size()});
        G[to].push_back((edge){from, 0, G[from].size()-1});
    }
    void bfs()
    {
        memset(d, -1, sizeof(d));
        queue<int>q;
        d[s] = 0;
        q.push(s);
        while(!q.empty()){
            int v = q.front();q.pop();
            for(int i = 0; i <G[v].size(); i++){
                edge &e = G[v][i];
                if(e.cap>0&&d[e.to]<0){
                    d[e.to] = d[v] + 1;
                    q.push(e.to);
                }
            }
        }
    }
    int dfs(int v, int f)
    {
        if(v==t) return f;
        for(int &i = iter[v]; i < G[v].size(); i++){
            edge &e = G[v][i];
            if(e.cap > 0 && d[v] < d[e.to]){
                int tf = dfs(e.to, min(f, e.cap));
                if(tf > 0){
                    e.cap -= tf;
                    G[e.to][e.rev].cap +=tf;
                    return tf;
                }
            }
        }
        return 0;
    }
    int max_flow()
    {
        int flow = 0;
        for(;;){
            bfs();
            if(d[t]<0) return flow;
            memset(iter, 0, sizeof(iter));
            int f;
            while((f = dfs(s, INF))>0){
                flow += f;
            }
        }
    }
    int main (void)
    {
        int N, F, D;scanf("%d%d%d",&N, &F, &D);
        int a, b;
        s = 2 * N + F + D + 1, t = s + 1;
        for(int i = 1; i <= N; i++){
            scanf("%d%d",&a, &b);
            add_edge(i, N + i, 1);
            for(int j = 0; j < a; j++){
                scanf("%d",&f[i][j]);
                add_edge(2 * N + f[i][j], i, 1);
            }
            for(int j = 0; j < b; j++){
                scanf("%d",&dr[i][j]);
                add_edge(N + i, 2 * N + F + dr[i][j], 1);
            }
        }
        for(int i = 1; i <= F; i++)
             add_edge(s, 2 * N + i, 1);
        for(int i = 1; i <= D; i++)
            add_edge(2 * N + F + i, t, 1);
    
        printf("%d
    ",max_flow());
    }
    

    增广路径必须满足的性质
    1.有奇数条边。
    2.起点在二分图的左半边,终点在右半边。
    3.路径上的点一定是一个在左半边,一个在右半边,交替出现。(其实二分图的性质就决定了这一点,因为二分图同一边的点之间没有边相连,不要忘记哦。)
    4.整条路径上没有重复的点。
    5.起点和终点都是目前还没有配对的点,而其它所有点都是已经配好对的。
    6.路径上的所有第奇数条边都不在原匹配中,所有第偶数条边都出现在原匹配中。
    7.最后,也是最重要的一条,把增广路径上的所有第奇数条边加入到原匹配中去,并把增广路径中的所有第偶数条边从原匹配中删除(这个操作称为增广路径的取反),则新的匹配数就比原匹配数增加了1个(奇数=偶数+1)。

  • 相关阅读:
    通过JavaScript垃圾回收机制来理解WeakSet/WeakMap中对象的弱引用
    json处理
    dotenv 加载本地环境变量
    各种ast库
    类型检测库
    npm 加解密库
    用计算机语言的爱情表白
    情侣在招聘会上搂抱招致企业反感
    《软件性能测试与LoadRunner实战》网上订购问题
    F1赛车的起源
  • 原文地址:https://www.cnblogs.com/Tuesdayzz/p/5758773.html
Copyright © 2011-2022 走看看