暑期ACM集训-网络流

HDU 3549

[problem]
网络流模板

#include<stdio.h>
#include<math.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<cstring>
#include<queue>
using namespace std;
#define inf  10000000
const int maxn = 1000;
struct edge{  int to, cap, rev;  };
vector<edge> G[maxn];
int level[maxn];
int iter[maxn];
int n, m, Case = 0;
void add_edge(int from, int to, int cap)  {
    G[from].push_back((edge){to, cap, G[to].size()}  );
    G[to].push_back((edge){from, 0, G[from].size() - 1});
}
void bfs(int s)  {
    memset(level, -1, sizeof(level));
    queue<int>  que;
    level[s] = 0;
    que.push(s);
    while(!que.empty())  {
        int v = que.front();  que.pop();
        for(int i = 0; i < G[v].size(); i++)  {
            edge &e = G[v][i];
            if (e.cap > 0 && level[e.to] < 0)  {
                level[e.to] = level[v] + 1;
                que.push(e.to);
            }
        }
    }
}
int dfs(int v, int t, int f)  {
    if (v == t)  return f;
    for(int &i = iter[v]; i < G[v].size(); i++)  {
        edge &e = G[v][i];
        if (e.cap > 0 && level[v] < level[e.to])  {
            int d = dfs(e.to, t, min(f, e.cap));
            if (d > 0)  {
                e.cap -= d;
                G[e.to][e.rev].cap += d;
                return d;
            }
        }
    }
    return 0;
}
int max_flow(int s, int t)  {
    int flow = 0;
    for(;;)  {
        bfs(s);
        if (level[t] < 0) return flow;
        memset(iter, 0, sizeof(iter));
        int f;
        while ((f = dfs(s, t, inf)) > 0)  flow += f;
    }
}

int main()
{
    int T;
    scanf("%d", &T);
    while (T--)  {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; i++)  G[i].clear();
        for(int i = 1; i <= m; i++)  {
            int x, y, z;
            scanf("%d%d%d", &x, &y, &z);
            add_edge(x, y, z);
        }
        int ans = max_flow(1, n);
        printf("Case %d: %d\n", ++Case, ans);
    }
    return 0;
}

HDU 3572 Task Schedule

[Problem]
给定n(200)个任务,m个机器,每个任务s[i], t[i], p[i]分别代表最早开始时间,最晚结束时间, 以及需要执行的时间,判断m个机器是否可以完成所有任务。
每个任务可以由不同机器间断性完成
[Solution]
每个任务可以由不同机器间断性完成,所以我们判断该任务在s[i]-t[i]时间内是否承担了P[i]的时间。
每一天抽象为一个点。
每个任务与源点连边,容量为p[i],每个任务与s[i]-t[i]的时间点连边,容量为1, 每个时间点与终点连边,容量为m,最后判断最大流与∑p[i]的关系即可

for(int i = 1; i <= n ;i++)  {
            int p, s, t;
            scanf("%d%d%d", &p, &s, &t);
            sum += p;
            add_edge(0, days + i, p);
            for(int j = s; j <= t; j++) add_edge(days + i, j, 1);
        }
        for(int i = 1; i <= days; i++)  add_edge(i, aim, m);
        int ans = max_flow(0, aim);

HDU 3081 Marriage Match II

[Problem]
给定n个女孩和n个男孩的相斥关系,每轮游戏每个女孩选择以前没有选过的一个男孩完成游戏,询问游戏最多可以玩多少轮。
[Solution]
二分 + 网络流
二分游戏进行轮数,问题便成了判断游戏是否可以进行mid轮。
原点与每个女孩连边,容量为mid,终点与男孩连边,容量为mid,不相斥的男孩与女孩连边,容量为1,最后判断最大流是否为mid * n

bool cal(int mid)  {
    int aim = n * 2 + 1;
    for(int i = 0; i <= aim; i++) G[i].clear();
    for(int i = 1; i <= n; i++)  add_edge(0, i, mid);
    for(int i = 1; i <= n; i++)  add_edge(i + n, aim, mid);
    for(int i = 1; i <= n ;i++)  {
        int k = find(i);
        for(int j = 1; j <= n; j++)  if (cnt[k][j] > 0) add_edge(i, j + n, 1);
    }
    int tot = max_flow(0, aim);
    return tot == mid * n;
}

HDU 3277 Marriage Match III

[Problem]
在上一题的基础上,为了让游戏进行更多轮,每个女孩可以选取任意的k个男孩作为自己的companion,询问最大轮数
[Solution]
在上一道题的基础上,每个女孩连接新的节点x,容量为k,x与所有与女孩相斥的男孩相连,容量为1

bool cal(int mid)  {
    int aim = n * 3 + 1;
    for(int i = 0; i <= aim; i++) G[i].clear();
    for(int i = 1; i <= n; i++)  add_edge(0, i, mid);
    for(int i = 1; i <= n; i++)  add_edge(i + n, aim, mid);
    for(int i = 1; i <= n ;i++)  {
        int k = find(i);
        for(int j = 1; j <= n; j++)  if (cnt[k][j] > 0) add_edge(i, j + n, 1);
    }
    for(int i = 1; i <= n; i++)  {
        add_edge(i, n * 2 + i, tt);
        int k = find(i);
        for(int j = 1; j <= n; j++)  if (cnt[k][j] == 0)  add_edge(n * 2 + i, j + n, 1);
    }
    int tot = max_flow(0, aim);
    return tot == mid * n;
}

HDU 3046 Pleasant sheep and big big wolf

[Problem]
给定矩阵,矩阵元素为1代表是羊,2代表狼,0代表空,在一些位置的边建上fence,使得狼无法到达羊的位置,询问最小fence
[Solution]
原点与羊连边,容量为inf, 终点与狼连边,容量为inf,每个位置与其可以到达的四个位置连边,容量为1,最后跑一边最小割

for(int i = 0; i <= aim; i++)  G[i].clear();
        for(int i = 1; i <= n; i++)  {
            for(int j = 1; j <= m; j++)  {
                scanf("%d", &a[i][j]);
                if (a[i][j] == 1)  add_edge(0, (i - 1) * m + j, inf);
                if (a[i][j] == 2)  add_edge((i - 1) * m + j, aim, inf);
                for(int v = 0; v < 4; v++)  {
                    int x = i + dx[v], y = j + dy[v];
                    if (x > 0 && x <= n && y > 0 && y <= m) add_edge((i - 1) * m + j, (x - 1) * m + y, 1);
                }
            }
        }
        int ans = max_flow(0, aim);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值