标签: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; }
这个题目的类型为:最大流受到两个互不影响的物体的影响,然后,我想着,如果物体的个数为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元饭钱
问如何招待顾客,可以让你得到最多的钱
自己思考后,又请教了几位大佬,最后的结论是:这个题无法求解...,至少缺乏高效的方法,如果有知道解法的大佬,请指教
标签:http ons tput map lse fine oid dinic img
原文地址:https://www.cnblogs.com/winter-bamboo/p/11380177.html