zoukankan      html  css  js  c++  java
  • [POJ3281]Dining 最大流(建图奇葩)

      题目链接:http://poj.org/problem?id=3281

      参考了某犇做的PPT。对于此题的解释有如下内容(我只是搬运工)。

      【题目大意】 有F种食物和D种饮料,每种食物或饮料只能供一头牛享用,且每头牛只享用一种食物和一种饮料。现在有N头牛,每头牛都有自己喜欢的食物种类列表和饮料种类列表,问最多能使几头牛同时享用到自己喜欢的食物和饮料。(1 <= F <= 100, 1 <= D <= 100, 1 <= N <= 100)

      此题的建模方法比较有开创性。以往一般都是左边一个点集表示供应并与源相连,右边一个点集表示需求并与汇相连。现在不同了,供应有两种资源,需求仍只有一个群体,怎么办?其实只要仔细思考一下最大流的建模原理,此题的构图也不是那么难想。最大流的正确性依赖于它的每一条s-t流都与一种实际方案一一对应。那么此题也需要用s-t流将一头牛和它喜欢的食物和饮料“串”起来,而食物和饮料之间没有直接的关系,自然就想到把牛放在中间,两边是食物和饮料,由s, t将它们串起来构成一种分配方案。至此建模的方法也就很明显了:每种食物i作为一个点并连边(s, i, 1),每种饮料j作为一个点并连边(j, t, 1),将每头牛k拆成两个点k’, k’’并连边(k’, k’’, 1), (i, k’, 1), (k’’, j, 1),其中i, j均是牛k喜欢的食物或饮料。求一次最大流即为结果。

    (牛必须放中间嗯)dinic板子,代码如下:

      1 #include <algorithm>
      2 #include <iostream>
      3 #include <iomanip>
      4 #include <cstring>
      5 #include <climits>
      6 #include <complex>
      7 #include <fstream>
      8 #include <cassert>
      9 #include <cstdio>
     10 #include <bitset>
     11 #include <vector>
     12 #include <deque>
     13 #include <queue>
     14 #include <stack>
     15 #include <ctime>
     16 #include <set>
     17 #include <map>
     18 #include <cmath>
     19 
     20 using namespace std;
     21 
     22 typedef struct Edge {
     23     int u, v, c, next;
     24 }Edge;
     25 
     26 const int inf = 0x7f7f7f7f;
     27 const int maxn = 2222;
     28 
     29 int cnt, head[maxn];
     30 int cur[maxn], dd[maxn];
     31 Edge edge[maxn<<1];
     32 
     33 int N, F, D;
     34 int n[maxn], f[maxn], d[maxn];
     35 int S, T;
     36 
     37 void init() {
     38     memset(head, -1, sizeof(head));
     39     for(int i = 0; i < maxn; i++) edge[i].next = -1;
     40     S = 0;
     41 }
     42 
     43 void adde(int u, int v, int c, int c1) {
     44     edge[cnt].u = u; edge[cnt].v = v; edge[cnt].c = c; 
     45     edge[cnt].next = head[u]; head[u] = cnt++;
     46     edge[cnt].u = v; edge[cnt].v = u; edge[cnt].c = c1; 
     47     edge[cnt].next = head[v]; head[v] = cnt++;
     48 }
     49 
     50 bool bfs(int s, int t, int n) {
     51     queue<int> q;
     52     for(int i = 0; i < n; i++) dd[i] = inf;
     53     dd[s] = 0;
     54     q.push(s);
     55     while(!q.empty()) {
     56         int u = q.front(); q.pop();
     57         for(int i = head[u]; ~i; i = edge[i].next) {
     58             if(dd[edge[i].v] > dd[u] + 1 && edge[i].c > 0) {
     59                 dd[edge[i].v] = dd[u] + 1;
     60                 if(edge[i].v == t) return 1;
     61                 q.push(edge[i].v);
     62             }
     63         }
     64     }
     65     return 0;
     66 }
     67 
     68 int dinic(int s, int t, int n) {
     69     int st[maxn], top;
     70     int u;
     71     int flow = 0;
     72     while(bfs(s, t, n)) {
     73         for(int i = 0; i < n; i++) cur[i] = head[i];
     74         u = s; top = 0;
     75         while(cur[s] != -1) {
     76             if(u == t) {
     77                 int tp = inf;
     78                 for(int i = top - 1; i >= 0; i--) {
     79                     tp = min(tp, edge[st[i]].c);
     80                 }
     81                 flow += tp;
     82                 for(int i = top - 1; i >= 0; i--) {
     83                     edge[st[i]].c -= tp;
     84                     edge[st[i] ^ 1].c += tp;
     85                     if(edge[st[i]].c == 0) top = i;
     86                 }
     87                 u = edge[st[top]].u;
     88             }
     89             else if(cur[u] != -1 && edge[cur[u]].c > 0 && dd[u] + 1 == dd[edge[cur[u]].v]) {
     90                 st[top++] = cur[u];
     91                 u = edge[cur[u]].v;
     92             }
     93             else {
     94                 while(u != s && cur[u] == -1) {
     95                     u = edge[st[--top]].u;
     96                 }
     97                 cur[u] = edge[cur[u]].next;
     98             }
     99         }
    100     }
    101     return flow;
    102 }
    103 
    104 int main() {
    105     // freopen("in", "r", stdin);
    106     while(~scanf("%d %d %d", &N, &F, &D)) {
    107         init();
    108         T = 2 * N + F + D + 1;
    109         int ff, dd;
    110         //把牛的位置拆开,放在食物和饮料中间
    111         //S指向食物,饮料指向T,牛指向牛
    112         for(int i = 1; i <= F; i++) adde(S, i, 1, 0);
    113         for(int i = 1; i <= D; i++) adde(2*N+F+i, T, 1, 0);
    114         for(int i = 1; i <= N; i++) adde(F+i, F+N+i, 1, 0);
    115         //确定食物指向牛、牛指向饮料的关系
    116         for(int i = 1; i <= N; i++) {
    117             int tmp;
    118             scanf("%d %d", &ff, &dd);
    119             for(int j = 0; j < ff; j++) {
    120                 scanf("%d", &tmp);
    121                 adde(tmp, F+i, 1, 0);
    122             }
    123             for(int j = 0; j < dd; j++) {
    124                 scanf("%d", &tmp);
    125                 adde(F+N+i, 2*N+F+tmp, 1, 0);
    126             }
    127         }
    128         printf("%d
    ", dinic(S, T, T+1));
    129     }
    130     return 0;
    131 }
  • 相关阅读:
    小伙创业做奶茶,兢兢业业把奶茶店已经扩张到了10家分店
    这个饭店每天只卖一道菜,月入百万?
    夫妻合力建大棚,种植辣椒和番茄,从此走上致富路
    下岗工人创业做办公设备,他将业务做的蒸蒸日上
    三十而立的他开始创业,打造旗舰网店,达到月销30万的传奇
    不断在创业路上寻找突破,他开店多家,没想到公司还上市了
    带着梦想和坚强,她收获了80后创业的广阔舞台,网站实现营利
    22岁开始创业,她把集团开到23家分店,营业额高达20亿元
    windows下git commit使用gvim编辑器
    windows下git commit使用gvim编辑器
  • 原文地址:https://www.cnblogs.com/kirai/p/4963293.html
Copyright © 2011-2022 走看看