首页 > 代码库 > hdu - 4971 - A simple brute force problem.(最大权闭合图)

hdu - 4971 - A simple brute force problem.(最大权闭合图)

题意:n(n <= 20)个项目,m(m <= 50)个技术问题,做完一个项目可以有收益profit (<= 1000),做完一个项目必须解决相应的技术问题,解决一个技术问题需要付出cost ( <= 1000),技术问题之间有先后依赖关系,求最大收益。

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

——>>项目必须解决相应的技术问题,技术问题之间也存在依赖,对应闭合图,最大收益对应最大权和。。于是,最大权闭合图,最小割,最大流上场。。

建图:

1)超级源S = n + m, 超级汇T = n + m + 1

2)对于每个项目i:S -> i (profit[i])

3)对于每个技术问题i:i + n -> T (cost[i])

4)对于项目 i 必须解决的技术问题 j:i -> j + n (INF)

5)对于技术问题 j 必须先解决的技术问题 i: i + n -> j + n (INF) (这里我觉得应为:j + n -> i + n (INF),这样理解才对,可是对不上样例,提交也WA。。)

然后,Dinic上场。。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>

using std::queue;
using std::min;

const int MAXN = 20 + 50 + 10;
const int MAXM = 20 + 1000 + 2500 + 50 + 10;
const int INF = 0x3f3f3f3f;

int n, m, sum;
int hed[MAXN];
int cur[MAXN], h[MAXN];
int ecnt;
int S, T;

struct EDGE
{
    int to;
    int cap;
    int flow;
    int nxt;
} edges[MAXM << 1];

void Init()
{
    ecnt = 0;
    memset(hed, -1, sizeof(hed));
    sum = 0;
}

void AddEdge(int u, int v, int cap)
{
    edges[ecnt].to = v;
    edges[ecnt].cap = cap;
    edges[ecnt].flow = 0;
    edges[ecnt].nxt = hed[u];
    hed[u] = ecnt++;
    edges[ecnt].to = u;
    edges[ecnt].cap = 0;
    edges[ecnt].flow = 0;
    edges[ecnt].nxt = hed[v];
    hed[v] = ecnt++;
}

void Read()
{
    int profit, cost, pc, tp;

    scanf("%d%d", &n, &m);
    S = n + m;
    T = n + m + 3;
    for (int i = 0; i < n; ++i)
    {
        scanf("%d", &profit);
        AddEdge(S, i, profit);
        sum += profit;
    }
    for (int i = 0; i < m; ++i)
    {
        scanf("%d", &cost);
        AddEdge(i + n, T, cost);
    }
    for (int i = 0; i < n; ++i)
    {
        scanf("%d", &pc);
        for (int j = 0; j < pc; ++j)
        {
            scanf("%d", &tp);
            AddEdge(i, tp + n, INF);
        }
    }
    for (int i = 0; i < m; ++i)
    {
        for (int j = 0; j < m; ++j)
        {
            scanf("%d", &tp);
            if (tp)
            {
                AddEdge(i + n, j + n, INF);
            }
        }
    }
}

bool Bfs()
{
    memset(h, -1, sizeof(h));
    queue<int> qu;
    qu.push(S);
    h[S] = 0;
    while (!qu.empty())
    {
        int u = qu.front();
        qu.pop();
        for (int e = hed[u]; e != -1; e = edges[e].nxt)
        {
            int v = edges[e].to;
            if (h[v] == -1 && edges[e].cap > edges[e].flow)
            {
                h[v] = h[u] + 1;
                qu.push(v);
            }
        }
    }

    return h[T] != -1;
}

int Dfs(int u, int cap)
{
    if (u == T || cap == 0) return cap;

    int flow = 0, subFlow;
    for (int e = cur[u]; e != -1; e = edges[e].nxt)
    {
        cur[u] = e;
        int v = edges[e].to;
        if (h[v] == h[u] + 1 && (subFlow = Dfs(v, min(cap, edges[e].cap - edges[e].flow))) > 0)
        {
            flow += subFlow;
            edges[e].flow += subFlow;
            edges[e ^ 1].flow -= subFlow;
            cap -= subFlow;
            if (cap == 0) break;
        }
    }

    return flow;
}

int Dinic()
{
    int maxFlow = 0;

    while (Bfs())
    {
        memcpy(cur, hed, sizeof(hed));
        maxFlow += Dfs(S, INF);
    }

    return maxFlow;
}

int main()
{
    int t, kase = 0;

    scanf("%d", &t);
    while (t--)
    {
        Init();
        Read();
        printf("Case #%d: %d\n", ++kase, sum - Dinic());
    }

    return 0;
}



hdu - 4971 - A simple brute force problem.(最大权闭合图)