网络流-最大流:两枚[poj1459&poj3436]

说说建图吧…

poj1459:

增加超级源点,超级汇点,跑一遍即可。

#include <cstdio>
#include <cstring>
#include <vector>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
using namespace std;

const int MAX = 107;
const int INF = 0xfffffff;
struct node {
    int to;
    int cap;
    int rev;
};
vector<node> G[MAX];
int level[MAX];
bool vis[MAX];
int n, np, nc, m, S, T;

inline void add_edge(int u, int v, int c) {
    G[u].push_back((node){v, c, G[v].size()});
    G[v].push_back((node){u, 0, G[u].size() - 1});
}

// from S to T, with max cap: C
bool BFS(int S, int T) {
    queue<int> Q;
    Q.push(S);
    memset(level, -1, sizeof(level));
    level[S] = 0;
    while (!Q.empty()) {
        int p = Q.front();
        Q.pop();
        for (vector<node>::iterator it = G[p].begin(); it != G[p].end(); ++it) {
            if (level[it->to] < 0 && it->cap > 0) {
                level[it->to] = level[p] + 1;
                Q.push(it->to);
                if (it->to == T) return true;
            }
        }
    }
    return false;
}

int DFS(int u, int v, int c) {
    if (u == v) return c;
    int sum = 0, tmp;
    for (vector<node>::iterator it = G[u].begin(); it != G[u].end(); ++it) {
        if (level[it->to] == level[u] + 1 && it->cap > 0) {
            tmp = DFS(it->to, T, min(c - sum, it->cap));
            sum += tmp;
            it->cap -= tmp;
            G[it->to][it->rev].cap += tmp;
        }
    }
    return sum;
}

int dinic(int S, int T) {
    int sum = 0;
    while (BFS(S, T)) {
        memset(vis, false, sizeof(vis));
        sum += DFS(S, T, INF);
    }
    return sum;
}

int main() {
    while (~scanf(" %d %d %d %d", &n, &np, &nc, &m)) {
        S = n, T = n + 1;
        for (int i = 0; i <= T; ++i) G[i].clear();
        int a, b, c;
        for (int i = 0; i < m; ++i) {
            scanf(" (%d,%d)%d", &a, &b, &c);
            add_edge(a, b, c);
        }
        for (int i = 0; i < np; ++i) {
            scanf(" (%d)%d", &a, &c);
            add_edge(S, a, c);
        }
        for (int i = 0; i < nc; ++i) {
            scanf(" (%d)%d", &a, &c);
            add_edge(a, T, c);
        }

        printf("%d\n", dinic(S, T));
    }

    return 0;
}

poj3436 ACM Computer Factory:

题意:

好多机器生产电脑,每台机器对应的P个元器件。

输入:

0表示不能有

1表示一定要有

2表示可有可无

输出:

0表示没有

1表示

另外还有一个流量值Q,即生产能力。

举例说明,如果有3种元器件,那么机器{15, [1, 2, 0], [1, 0, 1]}表示它可同时艹(即加工,编者注)15台产品{本题是生产电脑},并且拿给它加工的产品必须有元件1(不然可能产生故障),元件2可有可无(不影响),一定不能有元件3(不然卡住了就拔不出来了);同时,经过它加工后的产品会剩下元件1和元件3,不会有元件2.

深入理解后可以建图了:

①增加超级源点,超级汇点。对每个机器判断它是否能作为源点(输入的P的元器件要求不为’1’),是否能作为汇点(输出中P种原件均为’1’,也就是产品必须是完整哒)。对应与源汇点连边,容量INF。

②对每个机器,拆点,中间流量为对应那台机器的生产能力。

③ 两两检查每对机器,我们对每对组合判断一下:

如果对某元器件,机器1输出为x,机器2要求输入为y,那么

x,y=

0,0: OK

0,1: 不行

0,2:行

1,0:不行

1,1:行

1,2:行

所以只要检查

x+y==1?不行:行

即可。

#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <climits>
#include <algorithm>
using namespace std;

const int MAX = 55;
const int INF = 0xfffffff;
int G[MAX << 1][MAX << 1];
int in[MAX][MAX], out[MAX][MAX];
int level[MAX << 1];
int N, P;

struct o_o {
    int u;
    int v;
    int c;
};

bool BFS(int S, int T) {
    queue<int> Q;
    memset(level, -1, sizeof(level));
    Q.push(S);
    level[S] = 0;
    while (!Q.empty()) {
        int p = Q.front();
        Q.pop();
        if (p == T) return true;
        //这里务必保证T的标号最大
        for (int i = 0; i <= T; ++i) {
            if (level[i] == -1 && G[p][i] > 0) {
                level[i] = level[p] + 1;
                Q.push(i);
            }
        }
    }
    return false;
}

int DFS(int s, int t, int flow) {
    //printf("vis %d----------------\n", S);
    if (s == t) return flow;
    int sum = 0, tmp;
    for (int i = 0; i <= t; ++i) {
        if (level[i] == level[s] + 1 && G[s][i] > 0) {
            tmp = DFS(i, t, min(flow - sum, G[s][i]));
            sum += tmp;
            //printf("(%d,%d)\n", s, sum);
            G[s][i] -= tmp;
            G[i][s] += tmp;
        }
    }
    return sum;
}

int dinic(int S, int T) {
    int sum = 0;
    while (BFS(S, T)) {
        //puts("---------------");
        //for (int i = 0; i <= T; ++i) {
        //  printf("%d ", level[i]);
        //}
        //puts("\n----------------");
        sum += DFS(S, T, INF);
        //printf("sum = %d\n", sum);
        //puts("-----------------------");
        //getchar();
    }
    return sum;
}

int main() {
    int GT[MAX << 1][MAX << 1];
    while (~scanf(" %d %d", &P, &N)) {
        memset(G, 0, sizeof(G));
        for (int i = 1; i <= N; ++i) {
            //拆点
            scanf(" %d", &G[i][i + N]);
            for (int j = 1; j <= P; ++j) {
                scanf(" %d", &in[i][j]);
            }
            for (int j = 1; j <= P; ++j) {
                scanf(" %d", &out[i][j]);
            }
        }
        int S = 0, T = N << 1 | 1;
        for (int i = 1; i <= N; ++i) {
            bool flag1 = true, flag2 = true;;
            for (int j = 1; j <= P; ++j) {
                if (in[i][j] == 1) {
                    flag1 = false;
                }
                if (out[i][j] != 1) {
                    flag2 = false;
                }
            }
            if (flag1) G[S][i] = INF; //source
            if (flag2) G[i + N][T] = INF; //slink

            for (int j = 1; j <= N; ++j) {
                if (i == j) continue;
                flag1 = true;
                for (int k = 1; k <= P; ++k) {
                    if (out[i][k] + in[j][k] == 1) {
                        flag1 = false;
                        break;
                    }
                }
                if (flag1) G[i + N][j] = INF;
            }

        }
        memcpy(GT, G, sizeof(G));

        int ans = dinic(S, T);
        vector<o_o> V;
        o_o u_u;
        if (ans) {
            for (int i = 1; i < T; ++i) {
                for (int j = 1; j < T; ++j) {
                    if (G[i][j] < GT[i][j]) {
                        u_u.u = i > N ? i - N : i;
                        u_u.v = j > N ? j - N : j;
                        u_u.c = GT[i][j] - G[i][j];
                        if (u_u.u == u_u.v) continue;
                        V.push_back(u_u);
                    }
                }
            }
            printf("%d %d\n", ans, V.size());
            for (vector<o_o>::iterator it = V.begin(); it != V.end(); ++it) {
                printf("%d %d %d\n", it->u, it->v, it->c);
            }
        } else {
            puts("0 0");
        }
    }

    return 0;
}
时间: 2024-10-11 01:18:49

网络流-最大流:两枚[poj1459&poj3436]的相关文章

POJ训练计划3422_Kaka&#39;s Matrix Travels(网络流/费用流)

解题报告 题目传送门 题意: 从n×n的矩阵的左上角走到右下角,每次只能向右和向下走,走到一个格子上加上格子的数,可以走k次.问最大的和是多少. 思路: 建图:每个格子掰成两个点,分别叫"出点","入点", 入点到出点间连一个容量1,费用为格子数的边,以及一个容量∞,费用0的边. 同时,一个格子的"出点"向它右.下的格子的"入点"连边,容量∞,费用0. 源点向(0,0)的入点连一个容量K的边,(N-1,N-1)的出点向汇点连一

hdu 4289 Control(网络流 最大流+拆点)(模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4289 Control Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1545    Accepted Submission(s): 677 Problem Description You, the head of Department o

【bzoj1822】[JSOI2010]Frozen Nova 冷冻波 计算几何+二分+网络流最大流

题目描述 WJJ喜欢“魔兽争霸”这个游戏.在游戏中,巫妖是一种强大的英雄,它的技能Frozen Nova每次可以杀死一个小精灵.我们认为,巫妖和小精灵都可以看成是平面上的点. 当巫妖和小精灵之间的直线距离不超过R,且巫妖看到小精灵的视线没有被树木阻挡(也就是说,巫妖和小精灵的连线与任何树木都没有公共点)的话,巫妖就可以瞬间杀灭一个小精灵. 在森林里有N个巫妖,每个巫妖释放Frozen Nova之后,都需要等待一段时间,才能再次施放.不同的巫妖有不同的等待时间和施法范围,但相同的是,每次施放都可以

[笔记] 网络流-最大流 POJ-1273\HDU-4240

[1] POJ-1273 题目:http://poj.org/problem?id=1273 最直接的最大流问题,用了Ford-Fulkerson方法,DFS随机搜索增广路. 算法原理参考:http://blog.csdn.net/smartxxyx/article/details/9293665 /************************ POJ-1273* Ford-Fulkerson***********************/#include <stdio.h> #inclu

【网络流最大流】poj3281Dining

/* EK算法版本的,比较慢哦.....详见下面dinic版本 ----------------------------------------- 题目是网络流最大流的问题 ---------------------------------------- 建图: 关键:拆点 把每个牛拆成两个点,牛作为一个点有流量限制,即每一头牛只能的一份饭. 把牛拆开后,将边的权值赋值为1, ---------------------------------------- 建好图后就可以EK算法最大流了 ---

【bzoj1733】[Usaco2005 feb]Secret Milking Machine 神秘的挤奶机 二分+网络流最大流

题目描述 Farmer John is constructing a new milking machine and wishes to keep it secret as long as possible. He has hidden in it deep within his farm and needs to be able to get to the machine without being detected. He must make a total of T (1 <= T <=

POJ2135_Farm Tour(网络流/费用流)

解题报告 题目传送门 题意: 一个人有n个农场,他想从1到n去,有从n到1回来,要求路径最短,且没有走重复的路. 思路: 如果两次最短路感觉不行的,可以看成费用流,每一条路容量都是1,这样只要流量等于2就行了. 一次mcmf模版. #include <iostream> #include <cstring> #include <queue> #include <cstdio> #define inf 0x3f3f3f3f using namespace st

【bzoj3130】[Sdoi2013]费用流 二分+网络流最大流

题目描述 Alice和Bob做游戏,给出一张有向图表示运输网络,Alice先给Bob一种最大流方案,然后Bob在所有边上分配总和等于P的非负费用.Alice希望总费用尽量小,而Bob希望总费用尽量大.求两人都采取最优策略的情况下最大流及总费用. 输入 第一行三个整数N,M,P.N表示给定运输网络中节点的数量,M表示有向边的数量,P的含义见问题描述部分.为了简化问题,我们假设源点S是点1,汇点T是点N.接下来M行,每行三个整数A,B,C,表示有一条从点A到点B的有向边,其最大流量是C. 输出 第一

POJ训练计划2516_Minimum Cost(网络流/费用流)

解题报告 题意: 有n个商店,m个提供商,k种商品</span> n*k的矩阵,表示每个商店需要每个商品的数目: m*k矩阵,表示每个提供商拥有每个商品的个数 然后对于每个物品k,都有n*m的矩阵 i行j列表示 从j提供商向i商店运送一个k商品的代价是多少 判断所有的仓库能否满足所有客户的需求,如果可以,求出最少的运输总费用 思路: 建图的题,不能直接把所有信息建成图,因为n和m跟k都有关系,如果那样子建图的话,就要把k种拆成m类,每个仓库连向该仓库的第k种,然后再和n连线,有费用, 不过这样