HOJ 2634 网络流最小割 解题报告

2634 - How to earn more

Problem Description

Xiao Ming is an expert in computer science and technology, so he can get a lot of projects every month. The projects always bring him a lot of money, now he is thinking how to earn money as more as possible.
Every month he can get m projects, and each project Ai will bring him Xi yuan. Although Xiao Ming is an expert, he still needs to hire some other guys to help him. Of course, the employees are not as good as Xiao Ming, for they are just good at some single aspect. So, they should work together to finish one project. There is a list shows the salary of m employees, who are labeled from 0 to m-1. Xiao Ming only hires employees, in that list, and he knows who will be needed by each project.If one employee is hired, he can join in several projects.

Input

The first line is an integer c shows the number of cases. For each case, the first line has two numbers m,n(m,n <=100), denoting that there is m projects and n employees on the list.The second line has m integers, which are seperated by a single blank, the ith number Ximeans the project Ai will bring Xiao Ming Xi yuan. Xi is less the 10000. The third line has n integers, which are seperated by a single blank, the ith number Yimeans the employee Bi will cost Xiao Ming Yi yuan. And the next m lines will show which part of the employees will be needed by each project. Line i is a list of the employees, who are needed by project Ai. In each line, first a number Zi shows the number of employees needed by this project. And Zi labels of the emloyees follows, which are still seperated by a sigle blank.

Output

You should output a single integer shows the maximun money Xiao Ming can earn in a single month. The money he can earn is equall to the money he can totally get minus the money he totally cost. You should not leave any extra blanks at the end of each line.

Sample Input

1
3 5
30 40 43
55 17 23 22 11
3 0 1 2
3 1 2 3
2 2 1

Sample Output

21

[解题报告]
感觉有些小OJ不好找啊…传送门
题目大意
有M 个项目和N 个员工。做项目i 可以获得Ai 元,但是必须雇用若干个指定的 员工。雇用员工j 需要花费Bj 元,且一旦雇用,员工j 可以参加多个项目的开发.问经过合理的项目取舍,最多能挣多少钱。(1 <= M, N <= 100)
建模方法
此题是典型的“蕴含式最大获利问题”,套 用解决最大权闭合子图的建模方法即可解决。每个项目i 作为一个点并连边(s, i, Ai) ,每名员工j 作为一个点并连边(j, t, Bj),若项目 i 需要雇用员工j 则连边(i, j, ∞) 。
设最小割为ans,那么∑Ai-ans 即为结果。

代码如下:

#include<cstdio>
#include<cstring> 
#include<string>
#include<algorithm>
#include<map>
#include<queue>  
#include<vector>
using namespace std;  
#define inf 0x3f3f3f3f  
#define maxv 205
#define maxe 10005 

int nume=0,head[maxv],e[maxe][3];

void inline adde(int i,int j,int c)  
{  
    e[nume][0]=j;e[nume][1]=head[i];head[i]=nume;  
    e[nume++][2]=c; 
    e[nume][0]=i;e[nume][1]=head[j];head[j]=nume;  
    e[nume++][2]=0;  
}  

int ss,tt,n,m,t;  
int vis[maxv],lev[maxv]; 

bool bfs()  
{  
    for(int i=0;i<maxv;i++)  
    vis[i]=lev[i]=0;  
    queue<int>q;  
    q.push(ss);  
    vis[ss]=1;  
    while(!q.empty())  
    {  
        int cur=q.front();  
        q.pop();  
        for(int i=head[cur];i!=-1;i=e[i][1])  
        {  
            int v=e[i][0];  
            if(!vis[v]&&e[i][2]>0)  
            {  
                lev[v]=lev[cur]+1;  
                vis[v]=1;  
                q.push(v);  
            }  
        }  
    }  
    return vis[tt];  
}  
int dfs(int u,int minf)  
{  
    if(u==tt||minf==0) return minf;  
    int sumf=0,f;  
    for(int i=head[u];i!=-1&&minf;i=e[i][1])  
    {  
        int v=e[i][0];  
        if(lev[v]==lev[u]+1&&e[i][2]>0)  
        {  
            f=dfs(v,minf<e[i][2]?minf:e[i][2]);  
            e[i][2]-=f;e[i^1][2]+=f;  
            sumf+=f;minf-=f;  
        }  
    }  
    if(!sumf) lev[u]=-1;  
    return sumf;  
}  
int Dinic()  
{  
    int sum=0;  
    while(bfs()) sum+=dfs(ss,inf);  
    return sum;  
} 

int p[105],w[105];

int main()
{
    for(scanf("%d",&t);t;--t)
    {
        int sum=0;
        nume=0;
        memset(head,-1,sizeof(head));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;++i) {scanf("%d",&p[i]);sum+=p[i];}
        for(int i=1;i<=m;++i) scanf("%d",&w[i]);
        ss=0,tt=n+m+1;
        for(int i=1;i<=n;++i)
        {
            int c;scanf("%d",&c);
            while(c--)
            {
                int a;scanf("%d",&a);
                adde(i,n+a+1,inf);
            }
        }
        for(int i=1;i<=n;++i) adde(ss,i,p[i]);
        for(int i=1;i<=m;++i) adde(n+i,tt,w[i]);
        printf("%d\n",sum-Dinic());
    }   
    return 0;
}

让我看到你们的双手

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值