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
 


題意:

給出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;
}


發佈了119 篇原創文章 · 獲贊 10 · 訪問量 17萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章