码迷,mamicode.com
首页 > 其他好文 > 详细

HDU 4292 Food (建图思维 + 最大流)

时间:2019-08-19 22:57:49      阅读:91      评论:0      收藏:0      [点我收藏+]

标签:http   ons   tput   map   lse   fine   oid   dinic   img   

(点击此处查看原题)

题目分析

题意:某个餐馆出售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\n",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元饭钱

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

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

HDU 4292 Food (建图思维 + 最大流)

标签:http   ons   tput   map   lse   fine   oid   dinic   img   

原文地址:https://www.cnblogs.com/winter-bamboo/p/11380177.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!