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. 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个技术难关,每个技术难关都要通过培训员工来解决,并且要花费一定金钱。
每个工程都需要克服几个技术难关才能完成,技术难关数量也可以为0.
有的技术难关需要在其他技术难关克服的前提下才能克服。
问获得的最大利润为多少?
闭合图:一个有向图的子点集,使其中的点的出边都指回集合中的点,则称此为闭合图。
最大权闭合图:给每个点赋上点权,则权和最大的闭合图,为最大权闭合图。
闭合图的性质恰好反映了事件之间的必要条件的关系:一个事件发生,它需要的所有前提都要发生。
定义一个割划分出的S集合为一个解,那么割集的容量之和就是(未被选的A集合中的顶点的权值 + 被选的B集合中的顶点的权值),记为Cut。A集合中所有顶点的权值之和记为Total,那么Total - Cut就是(被选的A集合中的顶点的权值
- 被选的B集合中的顶点的权值),即为我们的目标函数,记为A。要想最大化目标函数A,就要尽可能使Cut小,Total是固定值,所以目标函数A取得最大值的时候,Cut最小,即为最小割。
//31MS 756K #include<stdio.h> #include<string.h> #include<algorithm> using namespace std; const int MAXN=20010;//点数的最大值 const int MAXM=880010;//边数的最大值 const int INF=0x3f3f3f3f; struct Node { int from,to,next; int cap; }edge[MAXM]; int tol; int head[MAXN]; int dis[MAXN]; int gap[MAXN];//gap[x]=y :说明残留网络中dis[i]==x的个数为y int nn;//nn是总的点的个数,包括源点和汇点 void init() { tol=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,int w) { edge[tol].from=u; edge[tol].to=v; edge[tol].cap=w; edge[tol].next=head[u]; head[u]=tol++; edge[tol].from=v; edge[tol].to=u; edge[tol].cap=0; edge[tol].next=head[v]; head[v]=tol++; } void BFS(int start,int end) { memset(dis,-1,sizeof(dis)); memset(gap,0,sizeof(gap)); gap[0]=1; int que[MAXN]; int front,rear; front=rear=0; dis[end]=0; que[rear++]=end; while(front!=rear) { int u=que[front++]; if(front==MAXN)front=0; for(int i=head[u];i!=-1;i=edge[i].next) { int v=edge[i].to; if(dis[v]!=-1)continue; que[rear++]=v; if(rear==MAXN)rear=0; dis[v]=dis[u]+1; ++gap[dis[v]]; } } } int SAP(int start,int end) { int res=0;nn=end+1; BFS(start,end); int cur[MAXN]; int S[MAXN]; int top=0; memcpy(cur,head,sizeof(head)); int u=start; int i; while(dis[start]<nn) { if(u==end) { int temp=INF; int inser; for(i=0;i<top;i++) if(temp>edge[S[i]].cap) { temp=edge[S[i]].cap; inser=i; } for(i=0;i<top;i++) { edge[S[i]].cap-=temp; edge[S[i]^1].cap+=temp; } res+=temp; top=inser; u=edge[S[top]].from; } if(u!=end&&gap[dis[u]-1]==0)//出现断层,无增广路 break; for(i=cur[u];i!=-1;i=edge[i].next) if(edge[i].cap!=0&&dis[u]==dis[edge[i].to]+1) break; if(i!=-1) { cur[u]=i; S[top++]=i; u=edge[i].to; } else { int min=nn; for(i=head[u];i!=-1;i=edge[i].next) { if(edge[i].cap==0)continue; if(min>dis[edge[i].to]) { min=dis[edge[i].to]; cur[u]=i; } } --gap[dis[u]]; dis[u]=min+1; ++gap[dis[u]]; if(u!=start)u=edge[S[--top]].from; } } return res; } int main() { int tt,cas=1,s,t,n,m; scanf("%d",&tt); while(tt--) { scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); init(); s=0; t=n+m+1; int a,num,sum=0; for(int i=1; i<=n; i++) { scanf("%d",&a); addedge(s,i,a); sum+=a; } for(int i=1; i<=m; i++) { scanf("%d",&a); addedge(n+m+i,t,a); addedge(n+i,t,a); } for(int i=1; i<=n; i++) { scanf("%d",&num); while(num--) { scanf("%d",&a); addedge(i,n+a+1,INF); } } for(int i=1; i<=m; i++) for(int j=1; j<=m; j++) { scanf("%d",&a); if(a)addedge(n+i,n+j,INF); } int ans=SAP(s,t); printf("Case #%d: %d\n",cas++,sum-ans); } return 0; }