HDU 4494 Teamwork(最大流或最小费用流)

来源:互联网 发布:东研网络 同花顺 编辑:程序博客网 时间:2024/05/22 12:21

题目链接:acm.hdu.edu.cn/showproblem.php?pid=4494


题意:相当于给n个任务,给出每个任务的开始时间和持续时间,每个任务需要不同种类的人来完成,种类之间的人彼此独立不能互换,对于某个任务的人在完成任务后可以赶往其他任务帮忙,问你最少需要多少人才能完成任务


思路:

最大流:这题和最小路径覆盖思想很像,只是每个点覆盖的次数不同了,所以可以拆点构建二分图,如果i能来得及赶上j的任务,那就连一条i到j'的边,流量为i点所拥有的人数,跑出的最大流即是所能节省下的最大人数,总人数相减即可


#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <utility>#include <cmath>#include <queue>#include <set>#include <map>#include <climits>#include <functional>#include <deque>#include <ctime>#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1 | 1#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int MAXN = 1000;const int MAXM = 50010;const int INF = 0x3f3f3f3f;struct Edge{    int to, next, cap, flow;} edge[MAXM];int tol;int head[MAXN];int gap[MAXN], dep[MAXN], cur[MAXN];void init(){    tol = 0;    memset(head, -1, sizeof(head));}void addedge(int u, int v, int w, int rw = 0){    edge[tol].to = v;    edge[tol].cap = w;    edge[tol].flow = 0;    edge[tol].next = head[u];    head[u] = tol++;    edge[tol].to = u;    edge[tol].cap = rw;    edge[tol].flow = 0;    edge[tol].next = head[v];    head[v] = tol++;}int Q[MAXN];void BFS(int start, int end){    memset(dep, -1, sizeof(dep));    memset(gap, 0, sizeof(gap));    gap[0] = 1;    int front = 0, rear = 0;    dep[end] = 0;    Q[rear++] = end;    while (front != rear)    {        int u = Q[front++];        for (int i = head[u]; i != -1; i = edge[i].next)        {            int v = edge[i].to;            if (dep[v] != -1)continue;            Q[rear++] = v;            dep[v] = dep[u] + 1;            gap[dep[v]]++;        }    }}int S[MAXN];int sap(int start, int end, int N){    BFS(start, end);    memcpy(cur, head, sizeof(head));    int top = 0;    int u = start;    int ans = 0;    while (dep[start] < N)    {        if (u == end)        {            int Min = INF;            int inser;            for (int i = 0; i < top; i++)                if (Min > edge[S[i]].cap - edge[S[i]].flow)                {                    Min = edge[S[i]].cap - edge[S[i]].flow;                    inser = i;                }            for (int i = 0; i < top; i++)            {                edge[S[i]].flow += Min;                edge[S[i] ^ 1].flow -= Min;            }            ans += Min;            top = inser;            u = edge[S[top] ^ 1].to;            continue;        }        bool flag = false;        int v;        for (int i = cur[u]; i != -1; i = edge[i].next)        {            v = edge[i].to;            if (edge[i].cap - edge[i].flow && dep[v] + 1 == dep[u])            {                flag = true;                cur[u] = i;                break;            }        }        if (flag)        {            S[top++] = cur[u];            u = v;            continue;        }        int Min = N;        for (int i = head[u]; i != -1; i = edge[i].next)            if (edge[i].cap - edge[i].flow && dep[edge[i].to] < Min)            {                Min = dep[edge[i].to];                cur[u] = i;            }        gap[dep[u]]--;        if (!gap[dep[u]])return ans;        dep[u] = Min + 1;        gap[dep[u]]++;        if (u != start)u = edge[S[--top] ^ 1].to;    }    return ans;}typedef long long ll;int n, m, g[MAXN][MAXN];ll x[MAXN], y[MAXN], s[MAXN], p[MAXN], t[MAXN];ll v[MAXN][10];ll dist(int i, int j){    return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);}int solve(int id){    init();    int s = 0, t = 2 * n + 1;    for (int i = 1; i <= n; i++)    {        addedge(s, i, v[i][id]);        addedge(i + n, t, v[i][id]);    }    for (int i = 1; i <= n; i++)        for (int j = 1; j <= n; j++)            if (g[i][j])                addedge(i, j + n, v[i][id]);    return sap(s, t, t + 1);}int main(){    int tt;    cin >> tt;    while (tt--)    {        ll sum = 0;        cin >> n >> m;        cin >> x[0] >> y[0];        n--;        for (int i = 1; i <= n; i++)        {            cin >> x[i] >> y[i] >> s[i] >> p[i];            t[i] = s[i] + p[i];            for (int j = 1; j <= m; j++)            {                cin >> v[i][j];                sum += v[i][j];            }        }        memset(g, 0, sizeof(g));        for (int i = 1; i <= n; i++)            for (int j = 1; j <= n; j++)            {                if (i == j) continue;                if (t[i] <= s[j] && dist(i, j) <= (s[j] - t[i]) * (s[j] - t[i]))                    g[i][j] = 1;            }        /* for(int i = 1; i <= n; i++)             {for(int j = 1; j <= n; j++)                 printf("%d ", g[i][j]);             printf("\n");             }*/        ll ans = 0;        for (int i = 1; i <= m; i++)            ans += solve(i);        cout << sum - ans << endl;    }    return 0;}


最小费用流:仍是每个点拆成两个,原有的点代表自身任务,然后源点向这些点连一条流量为该点所需人数费用为1的边,这些点再向汇点连边,新拆出的点用来为其他点提供人数,流量为该点人数,费用为0


#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#include <vector>#include <utility>#include <cmath>#include <queue>#include <set>#include <map>#include <climits>#include <functional>#include <deque>#include <ctime>#define lson l, mid, rt << 1#define rson mid + 1, r, rt << 1 | 1#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;const int MAXN = 1000;const int MAXM = 50000;const int INF = 0x3f3f3f3f;typedef long long ll;struct Edge{    int to, next, cap, flow, cost;} edge[MAXM];int head[MAXN], tol;int pre[MAXN], dis[MAXN];bool vis[MAXN];int N;//节点总个数,节点编号从0~N-1void init(int n){    N = n;    tol = 0;    memset(head, -1, sizeof(head));}void addedge(int u, int v, int cap, int cost){    edge[tol].to = v;    edge[tol].cap = cap;    edge[tol].cost = cost;    edge[tol].flow = 0;    edge[tol].next = head[u];    head[u] = tol++;    edge[tol].to = u;    edge[tol].cap = 0;    edge[tol].cost = -cost;    edge[tol].flow = 0;    edge[tol].next = head[v];    head[v] = tol++;}bool spfa(int s, int t){    queue<int>q;    for (int i = 0; i < N; i++)    {        dis[i] = INF;        vis[i] = false;        pre[i] = -1;    }    dis[s] = 0;    vis[s] = true;    q.push(s);    while (!q.empty())    {        int u = q.front();        q.pop();        vis[u] = false;        for (int i = head[u]; i != -1; i = edge[i].next)        {            int v = edge[i].to;            if (edge[i].cap > edge[i].flow &&                    dis[v] > dis[u] + edge[i].cost )            {                dis[v] = dis[u] + edge[i].cost;                pre[v] = i;                if (!vis[v])                {                    vis[v] = true;                    q.push(v);                }            }        }    }    if (pre[t] == -1) return false;    else return true;}//返回的是最大流,cost存的是最小费用int minCostMaxflow(int s, int t, int &cost){    int flow = 0;    cost = 0;    while (spfa(s, t))    {        int Min = INF;        for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])        {            if (Min > edge[i].cap - edge[i].flow)                Min = edge[i].cap - edge[i].flow;        }        for (int i = pre[t]; i != -1; i = pre[edge[i ^ 1].to])        {            edge[i].flow += Min;            edge[i ^ 1].flow -= Min;            cost += edge[i].cost * Min;        }        flow += Min;    }    return flow;}int n, m, g[MAXN][MAXN];ll x[MAXN], y[MAXN], s[MAXN], p[MAXN], t[MAXN];ll v[MAXN][10];ll dist(int i, int j){    return (x[i] - x[j]) * (x[i] - x[j]) + (y[i] - y[j]) * (y[i] - y[j]);}int solve(int id){    int s = 0, t = 2 * n + 1;    init(t + 1);    for (int i = 1; i <= n; i++)    {        addedge(s, i, v[i][id], 1);        addedge(s, i + n, v[i][id], 0);        addedge(i, t, v[i][id], 0);    }      for (int i = 1; i <= n; i++)        for (int j = 1; j <= n; j++)            if (g[i][j])                addedge(i + n, j, v[i][id], 0);    //  for (int i = 0; i < tol; i++)    //  printf("%d %d %d\n", edge[i].to, edge[i].cap, edge[i].cost);    int cost;    minCostMaxflow(s, t, cost);    return cost;}int main(){    int tt;    cin >> tt;    while (tt--)    {        cin >> n >> m;        cin >> x[0] >> y[0];        n--;        for (int i = 1; i <= n; i++)        {            cin >> x[i] >> y[i] >> s[i] >> p[i];            t[i] = s[i] + p[i];            for (int j = 1; j <= m; j++)                cin >> v[i][j];        }        memset(g, 0, sizeof(g));        for (int i = 1; i <= n; i++)            for (int j = 1; j <= n; j++)            {                   if(i == j) continue;                if (t[i] <= s[j] && dist(i, j) <= (s[j] - t[i]) * (s[j] - t[i]))                    g[i][j] = 1;            }        /* for(int i = 1; i <= n; i++)             {for(int j = 1; j <= n; j++)                 printf("%d ", g[i][j]);             printf("\n");             }*/        int ans = 0;        for (int i = 1; i <= m; i++)            ans += solve(i);        cout << ans << endl;    }    return 0;}



0 0