HOJ 2634 How to earn more //最小割

最大收益项目调度
本文介绍了一个计算机科学专家如何通过合理分配项目和员工实现收益最大化的问题。通过构建特定的图模型并利用最小割最大流原理求解,最终实现利益最大化。

How to earn more

Time limit:1sec.Submitted:185
Memory limit:64MAccepted:109
Source: ww

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

 

 

Hint

 

If Xiao Ming can do less project to earn more money, he will certainly do that.
Statistic     Status   Submit   Solution   Discuss    Print
[ Back ]

 

 

整个建图过程参考了这个大牛,http://hi.baidu.com/nicyun/blog/item/c02909301cd18a9ca8018e69.html

 

 

题目大意:有m个项目要做,有n个工人能做,每个项目要且必须要这些工人中的一个子集来完成,给出每个项目完成后的收益gi和雇佣每个工人的花费ci,以及每个项目必须需要的工人的编号,问能获得的最大收益是多少。

先构图,记起始点为s汇点为t,从s到每个工人wi连一条边容量为ci,从每个项目pi到t连一条边容量为gi,然后若项目pi需要工人wi来完成,则从wi到pi连一条边容量为无穷大。

现在看看此图的最小割有什么含义。(设由最小割划分开与s相连的子图为S,与t相连的子图为T,T中的项目和工人称为被选中的)

1. 若选中的项目pi在T中,因为割中不可能有无限容量的边,则完成此项目所需要的工人也必在T中,这样就保证了割对应的是一个可行的方案。

2. s到每个工人wi的边如果在割中,则此工人是被选中的,如果不在则是未被选中的。

3. 相反,项目pi到t的边如果在割中,则此项目是未被选中的,如果不在则是被选中的。(画个图看看就明白了)

4. 可得出最小割的容量为:被选中的工人花费 + 未被选中的项目收入(1)

又 未被选中的项目收入 = 总的项目收入 - 选中的项目收入(2)

所以可得割的容量为: 总的项目收入 - (被选中的项目收入 - 被选中的工人花费)

可以看出括号中的即为题目要求的ans,设总的项目收入为E,由最小割 == 最大流的定理可得:

ans = E - MaxFlow

 

 

 

 

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,flow[210][210],dist[210],gap[210];
int find_path(int p, int limit=1<<30-1)
{
    if (p == n - 1) return limit;
    for (int i = 0; i < n; ++i)
    {
        if (dist[p] == dist[i] + 1 && flow[p][i] > 0)
        {
            int t = find_path(i, min(limit, flow[p][i]));
            if (t < 0) return t;
            if (t > 0)
            {
                flow[p][i] -= t;
                flow[i][p] += t;
                return t;
            }
        }
    }
    int label = n;
    for (int i = 0; i < n; ++i)
        if (flow[p][i] > 0) label = min(label, dist[i] + 1);
    if (--gap[dist[p]] == 0 || dist[0] >= n) return -1;
    ++gap[dist[p] = label];
    return 0;
}
int iSAP()
{
    gap[0] = n;
    int maxflow = 0,t = 0;
    while ((t = find_path(0)) >= 0) maxflow += t;
    return maxflow;
}
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(flow,0,sizeof(flow));
        memset(gap,0,sizeof(gap));
        memset(dist,0,sizeof(dist));
        scanf("%d%d",&n,&m);
        int sum=0;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            flow[i+m][n+m+1]=x;
            sum+=x;
        }
        for(int i=1;i<=m;i++)
        {
            int x;
            scanf("%d",&x);
            flow[0][i]=x;
        }
        for(int i=1;i<=n;i++)
        {
            int t,x;
            scanf("%d",&t);
            for(int j=1;j<=t;j++)
            {
                scanf("%d",&x);
                x++;
                flow[x][i+m]=1<<30-1;
            }
        }
        n=n+m+2;
        printf("%d/n",sum-iSAP());
    }
    return 0;
}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值