zoukankan      html  css  js  c++  java
  • HDU 4292 Food (建图思维 + 最大流)

    (点击此处查看原题)

    题目分析

    题意:某个餐馆出售f种食物,d种饮料,其中,第i种食物有fi份,第i种饮料有di份;此时有n个人来餐馆吃饭,这n个人必须有一份食物和一份饮料才会留下来吃饭,否则,他将离去,而且每个人只吃某几种食物和饮料,如果某个人留下来,那么必须提供一份他吃的食物和一份他吃饮料,问在这种情况下,最多可以招待多少人。

    思路:这类的题目我总结为:最大流受到两个互不影响的物体的影响,这类题目为最大流题目,建边如下:

    1)由源点向每一种食物i代表的结点建一条容量为fi的边

    2)将每个顾客代表的结点拆成左结点和右结点,由左结点向右结点建一条容量为1的边

    3)由每一种食物i代表的结点向对应顾客的左端点建一条容量为1的边(代表某一顾客可以食用这一食物)

    4)由每个顾客的右端点向其可食用的饮料代表的结点i建一条容量为1的边

    5)由每个饮料代表的结点i向汇点建一条容量为di的边

    最后,跑出来的最大流即为答案。

    (这个题的数据其实还是比较大的,边的总数超过1e5,注意一下就好)

    代码区

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<string>
    #include<fstream>
    #include<vector>
    #include<stack>
    #include <map>
    #include <iomanip>
    
    #define bug cout << "**********" << endl
    #define show(x, y) cout<<"["<<x<<","<<y<<"] "
    #define LOCAL = 1;
    using namespace std;
    typedef long long ll;
    const int inf = 0x3f3f3f3f;
    const ll mod = 998244353;
    const int Max = 1e5 + 10;
    const int Max2 = 1e3 + 10;
    
    struct Edge
    {
        int to, next, flow;
    } edge[Max<<1];
    
    int n, f, d, s, t;
    int head[Max], tot;
    int dis[Max];
    
    void init()
    {
        memset(head, -1, sizeof(head));
        tot = 0;
        s = 0;
        t = f + d + 2 * n + 1;
    }
    
    void add(int u, int v, int flow)
    {
        edge[tot].to = v;
        edge[tot].flow = flow;
        edge[tot].next = head[u];
        head[u] = tot++;
    }
    
    bool bfs()            //判断连通性,将图分层次
    {
        queue<int>q;
        memset(dis, -1, sizeof(dis));
        dis[s] = 0;
        q.push(s);        //源点
        while (!q.empty())
        {
            int u = q.front();q.pop();
    
            for (int i = head[u]; i != -1; i = edge[i].next)
            {
                int v = edge[i].to;
                if (dis[v] == -1 && edge[i].flow > 0)
                {
                    dis[v] = dis[u] + 1;
                    q.push(v);
                    if (v == t) return true;
                }
            }
        }
        return false;
    }
    
    int dfs(int u, int flow_in)
    {
        if (u == t) return flow_in;
        int flow_out = 0;            //实际流出流量
        for (int i = head[u];i != -1;i = edge[i].next)
        {
            int v = edge[i].to;
            if (dis[v] == dis[u] + 1 && edge[i].flow > 0)
            {
                int flow_part = dfs(v, min(flow_in, edge[i].flow));
                if (flow_part == 0)continue;    //无法形成增广路
                flow_in -= flow_part;
                flow_out += flow_part;
                edge[i].flow -= flow_part;
                edge[i ^ 1].flow += flow_part;
                if (flow_in == 0)break;
            }
        }
        return flow_out;
    }
    
    int Dinic()
    {
        int sum = 0;
        while (bfs())
        {
            sum += dfs(s, inf);
        }
        return sum;
    }
    
    
    
    int main()
    {
    #ifdef LOCAL
        //freopen("input.txt", "r", stdin);
        //freopen("output.txt", "w", stdout);
    #endif
        while (scanf("%d%d%d", &n, &f, &d) != EOF)
        {
            init();                                    //s:0 ; f: 1~F ; man: F+1~F+2*n ; d: F+2*n+1~F+2*n+D ; t: F+2*n+D+1
            for (int i = 1, flow; i <= f; i++)
            {
                scanf("%d", &flow);
                add(s, i, flow);
                add(i, s, 0);                    //由源点向F建边权为fi的边
            }
            for (int i = f + 2 * n + 1, flow; i <= f + 2 * n + d; i++)
            {
                scanf("%d", &flow);
                add(i, t, flow);
                add(t, i, 0);                     //由D向汇点建边权为di的边
            }
            for (int i = f + 1; i <= f + n; i ++)
            {
                add(i, i + n, 1);
                add(i + n, i, 0);              //拆点
                char str[205];
                scanf("%s", str);
                for (int j = 1; j <= f; j++)
                {
                    if (str[j - 1] == 'Y')
                    {
                        add(j, i, 1);
                        add(i, j, 0);             //由F向顾客建一条容量为1的边
                    }
                }
            }
            for (int i = f + 1; i <= f + n; i++)
            {
                char str[205];
                scanf("%s",str);
                for(int j = f + 2 * n + 1; j <= f +2 * n + d; j ++)
                {
                    if(str[j-f-2*n-1] == 'Y')
                    {
                        add(i+n, j, 1);
                        add(j, i+n, 0);             //由顾客向D建一条容量为1的边
                    }
                }
            }
            printf("%d
    ",Dinic());
        }
        return 0;
    }
    View Code

     扩展

    这个题目的类型为:最大流受到两个互不影响的物体的影响,然后,我想着,如果物体的个数为3个或者3个以上,那么该如何建图呢?比如说下面这个题目:

    有一个餐馆,有A种饭,B种菜,C种汤,其中第i种饭有ai份(1<=i<=A),第i种菜有bi份(1<=i<=B),第i种汤有ci份(1<=i<=C)

    此时有n个人进入餐馆用餐,已知每个人必须选择1份饭,1份菜和1份汤,

    而且第i个人只吃qi种饭,分别为x1,x2….xq1,同时也只吃wi种菜,分别为y1,y2…yw1,只吃ei种汤,分别为z1,z2…zei

    如果某个人无法得到他需要的一饭一菜一汤,他将离去。不会付款,也不会消耗任何事物。如果某个人如果得到了他所需的所有食物,他将给与你vali元饭钱

    问如何招待顾客,可以让你得到最多的钱

    自己思考后,又请教了几位大佬,最后的结论是:这个题无法求解...,至少缺乏高效的方法,如果有知道解法的大佬,请指教

  • 相关阅读:
    JVM启动参数小结
    Java 线程池学习
    myeclipse 8.5安装freemarker插件方法
    开源文件比较工具:WinMerge、KDiff3、diffuse
    初探淘宝技术构架
    Java获取IP地址:request.getRemoteAddr()注意
    Spring MVC 教程,快速入门,深入分析
    分布式服务框架 Zookeeper -- 管理分布式环境中的数据
    YARN作业提交流程剖析
    经典的MapReduce1解析
  • 原文地址:https://www.cnblogs.com/winter-bamboo/p/11380177.html
Copyright © 2011-2022 走看看