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