HDU 4971 A simple brute force problem.(最小割,最大权闭合图)

http://acm.hdu.edu.cn/showproblem.php?pid=4971

A simple brute force problem.
Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 182    Accepted Submission(s): 115

Problem Description

There‘s a company with several projects to be done. Finish a project will get you profits. However, there are some technical problems for some specific projects. To solve the problem, the manager will train his employee which may cost his budget. There may
be dependencies between technical problems, for example, A requires B means you need to solve problem B before solving problem A. If A requires B and B requires A, it means that you should solve them at the same time. You can select which problems to be solved
and how to solve them freely before finish your projects. Can you tell me the maximum profit?

Input

The first line of the input is a single integer T(<=100) which is the number of test cases.

Each test case contains a line with two integer n(<=20) and m(<=50) which is the number of project to select to complete and the number of technical problem.

Then a line with n integers. The i-th integer(<=1000) means the profit of complete the i-th project.

Then a line with m integers. The i-th integer(<=1000) means the cost of training to solve the i-th technical problem.

Then n lines. Each line contains some integers. The first integer k is the number of technical problems, followed by k integers implying the technical problems need to solve for the i-th project.

After that, there are m lines with each line contains m integers. If the i-th row of the j-th column is 1, it means that you need to solve the i-th problem before solve the j-th problem. Otherwise the i-th row of the j-th column is 0.

Output

For each test case, please output a line which is "Case #X: Y ", X means the number of the test case and Y means the the maximum profit.

Sample Input

4
2 3
10 10
6 6 6
2 0 1
2 1 2
0 1 0
1 0 0
0 0 0
2 3
10 10
8 10 6
1 0
1 2
0 1 0
1 0 0
0 0 0
2 3
10 10
8 10 6
1 0
1 2
0 1 0
0 0 0
0 0 0
2 3
10 10
8 10 6
1 0
1 2
0 0 0
1 0 0
0 0 0

Sample Output

Case #1: 2
Case #2: 4
Case #3: 4
Case #4: 6

Source

2014 Multi-University Training Contest 10

题意:

给出n个项目,m个问题,完成某个项目需要解决一些问题,解决某个问题可能要先解决另一个问题,比如问题i依赖于问题j,那要先解决j再解决i,如果互相依赖,则要同时解决。完成某个项目会获得收益,解决某个问题需要一些花费,求最大净收益。

分析:

一点开题就感觉是个网络流,不过一直没想到该怎么建图,后来队友切了签到题发现这题其他队过得有点快,就感觉应该是个乱搞的搜索(当然,乱搜确实能过),后来看到一道做过的网络流就很高兴地去切了,切完后我又想了下这题,发现就是个最大权闭合图,幸好以前做过一道,并且还记得建图的方法,于是在刚过的网络流的代码上改了两下就AC了。

建图方法:项目是正权点,权值为收益,问题为负权点,权值为花费。项目对所要解决的问题连边,容量为INF;增加源点,连向正权点,容量为收益;增加汇点,负权点向其连边,容量为花费。最大权和为正权和减去上图中的最小割。

#include <cstdio>
#include <algorithm>
#include <cstring>
#define LL long long
#define itn int
#define maxn 1007
#define maxm 2333333
#define INF 0x3f3f3f3f
using namespace std;

int a[maxn],b[maxn];
int fir[maxn];
itn u[maxm],v[maxm],cap[maxm],flow[maxm],nex[maxm];
int e_max;
itn q[maxn<<2];

itn lv[maxn],iter[maxn];

void add_edge(int _u,int _v,int _w)
{

    int e=e_max++;
    u[e]=_u;v[e]=_v;cap[e]=_w;
    nex[e]=fir[u[e]];fir[u[e]]=e;
    e=e_max++;
    u[e]=_v;v[e]=_u;cap[e]=0;
    nex[e]=fir[u[e]];fir[u[e]]=e;
}

void dinic_bfs(itn s)
{
    int f,r;
    lv[s]=0;
    q[f=r=0]=s;

    while (f<=r)
    {
        int x=q[f++];
        for (int e=fir[x];~e;e=nex[e])
        {
            if (cap[e]>flow[e] && lv[v[e]]<0)
            {
                lv[v[e]]=lv[u[e]]+1;
                q[++r]=v[e];
            }
        }
    }
}

int dinic_dfs(int s,int t,int _f)
{
    if (s==t)   return _f;

    for (int &e=iter[s];~e;e=nex[e])
    {
        if (cap[e]>flow[e] && lv[s]<lv[v[e]])
        {
            int _d=dinic_dfs(v[e],t,min(cap[e]-flow[e],_f));
            if (_d>0)
            {
                flow[e]+=_d;
                flow[e^1]-=_d;
                return _d;
            }
        }
    }

    return 0;
}

itn max_flow(int s,int t)
{
    int total_flow=0;

    memset(flow,0,sizeof flow);
    for (;;)
    {
        memset(lv,-1,sizeof lv);
        dinic_bfs(s);

        if (lv[t]==-1)  break;

        memcpy(iter,fir,sizeof fir);

        itn _f=0;
        while ((_f=dinic_dfs(s,t,INF))>0)
            total_flow+=_f;

    }

    return total_flow;

}

int main()
{
    int n,m;
    itn T_T,cas=0;
    scanf("%d",&T_T);

    while(T_T--)
    {
        printf("Case #%d: ",++cas);
        scanf("%d%d",&n,&m);
        itn s=0,t=n+m+1;
        itn sr=0,sc=0;
        e_max=0;
        memset(fir,-1,sizeof fir);
        for (int i=1;i<=n;i++)
        {
            scanf("%d",a+i);
            add_edge(s,i,a[i]);
            sr+=a[i];
        }

        for (int i=1;i<=m;i++)
        {
            scanf("%d",b+i);
            add_edge(i+n,t,b[i]);
        }

        for (int i=1,k,p;i<=n;i++)
        {
            scanf("%d",&k);
            for (int j=0;j<k;j++)
            {
                scanf("%d",&p);
                p++;
                add_edge(i,p+n,INF);
            }

        }

        int x;
        for (int i=1;i<=m;i++)
        {
            for (int j=1;j<=m;j++)
            {
                scanf("%d",&x);
                if (x)
                add_edge(i+n,j+n,INF);
            }
        }

        int res=sr-max_flow(s,t);

        printf("%d\n",res);
    }

    return 0;
}
时间: 2024-10-26 23:38:15

HDU 4971 A simple brute force problem.(最小割,最大权闭合图)的相关文章

HDU 4971 A simple brute force problem.(最小割---最大权闭合)

题目地址:HDU 4971 比赛的时候还不会最大权闭合,当时还跟队友讨论了好长时间费用流和DP..现在看来就是一最大权闭合水题... 建图思路:源点连工程,权值为利润,汇点连科技项目,权值为花费,然后对有依赖性的连有向边.用正权值和减去最小割就是答案. #include <iostream> #include <cstdio> #include <string> #include <cstring> #include <stdlib.h> #in

【最小割】HDU 4971 A simple brute force problem.

说是最大权闭合图.... 比赛时没敢写.... 题意 一共有n个任务,m个技术 完成一个任务可盈利一些钱,学习一个技术要花费钱 完成某个任务前需要先学习某几个技术 但是可能在学习一个任务前需要学习另几个任务 求最多能赚多少钱咯 先将缩点将需要一起学掉的技术缩成一个点 建s--任务 权值为该任务盈利多少钱 建技术(缩点后)-t 权值为学习这技术的花费(总) 任务-技术 (完成该任务所需的每个技术都需要建边)权值为INF #include<stdio.h> #include<stdlib.h

HDU 4971 A simple brute force problem.(dp)

HDU 4971 A simple brute force problem. 题目链接 官方题解写的正解是最大闭合权,但是比赛的时候用状态压缩的dp也过掉了- -,还跑得挺快 思路:先利用dfs预处理出每个项目要完成的技术集合,那么dp[i][j]表示第i个项目,已经完成了j集合的技术,由于j这维很大,所以利用map去开数组 代码: #include <cstdio> #include <cstring> #include <algorithm> #include &l

HDU - 4971 A simple brute force problem. (DP)

Problem Description There's a company with several projects to be done. Finish a project will get you profits. However, there are some technical problems for some specific projects. To solve the problem, the manager will train his employee which may

HDU 4971 A simple brute force problem. 强连通缩点+最大权闭合图

题意: 给定n个项目,m个技术难题 下面一行n个数字表示每个项目的收益 下面一行m个数字表示攻克每个技术难题的花费 下面n行第i行表示 第一个数字u表示完成 i 项目需要解决几个技术难题,后面u个数字表示需要解决的问题标号. 下面m*m的矩阵 (i,j) = 1 表示要解决j问题必须先解决i问题. (若几个问题成环,则需要一起解决) 问:最大收益. 思路: 先给问题缩点一下,每个缩点后的点权就是这个点内所有点权和. 然后跑一个最大权闭合图. #include<stdio.h> #include

HDU 4971 A simple brute force problem.

A simple brute force problem. Time Limit: 1000ms Memory Limit: 65536KB This problem will be judged on HDU. Original ID: 497164-bit integer IO format: %I64d      Java class name: Main There's a company with several projects to be done. Finish a projec

HDU 4971 A simple brute force problem. 最大权闭合图

点击打开链接 A simple brute force problem. Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 157    Accepted Submission(s): 99 Problem Description There's a company with several projects to be done. Fi

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

题意:n个项目m个问题,完成每个项目有对应收入,解决每个问题需要对应花费, 给出每个项目需解决的问题以及各问题间的依赖关系,求最大利润(可完成部分或全部项目): 思路:网络流中的最大权闭合图的典型应用——利润问题,参考07年day2国家集训队胡伯涛的论文: 参考:http://blog.csdn.net/u012965890/article/details/38761043 闭合图指所有顶点的出边指向的所有顶点均在图中: 最大权闭合图:点权和最大的闭合图,即权值最大的子闭合图: 建图思路: 工程

hdoj 4971 A simple brute force problem. 【最大闭合权 --&gt; 最小割】

题目:hdoj 4971 A simple brute force problem. 题意:给出 n 个任务和 m 项技术,完成某个任务需要其中几项技术,完成某个任务有奖金,学习某个技术需要钱,技术之间有父子关系,某项技术可能需要先学习其他技术,然后问你选择做那些任务获得收益最大? 分析:看题意的黑体字部分,就是一个标准的闭合权问题,这个题目的关键忽悠点在于技术之间的关系,导致很多人想到了dp以及树形dp. 其实就是一个闭合权问题模板,官方题解说如果技术之间存在相互的关系需要缩点,其实不用缩点也