点击打开链接
题意:n个工程,每个工程完成后会有利润,但是完成每个工程都需要克服一些难题,每个难题都会消耗资金,而且有的难题会有一些特殊要求,那就是在完成它的时候它希望有的难题已经完成,这会在输入下面的矩阵中体现出来
思路:经典的网络流24题里面一道题的变形嘛,求最大权闭合图,这个也就等于利润总和-最小割,我的总利润就那么多,我希望的是消耗资金越少越好,也就是最小割,然后结果就出来了,但是和24题那题的区别是这里的有些难题会希望自己被完成时有的难题已经完成,那没问题,既然你想和我一起分享这些资金,我就连一条inf的边到你身上,例如现在跑到1上的流量为10,而1希望2也被完成,那么这10流量就继续往下跑,跑到2上去,这样流出来的流量就是就是消耗的
#include <queue> #include <vector> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int inf=0x3f3f3f3f; const int maxn=150; struct edge{ int to,cap,rev; edge(); edge(int a,int b,int c){to=a;cap=b;rev=c;}; }; vector<edge>G[maxn]; int dis[maxn],iter[maxn],num[maxn],num1[maxn]; void addedge(int st,int en,int val){ G[st].push_back(edge(en,val,G[en].size())); G[en].push_back(edge(st,0,G[st].size()-1)); } void bfs(int st){ memset(dis,-1,sizeof(dis)); queue<int>que;dis[st]=0; que.push(st); while(!que.empty()){ int v=que.front();que.pop(); for(unsigned int i=0;i<G[v].size();i++){ edge &e=G[v][i]; if(e.cap>0&&dis[e.to]<0){ dis[e.to]=dis[v]+1; que.push(e.to); } } } } int dfs(int st,int en,int f){ if(st==en) return f; for(int &i=iter[st];i<G[st].size();i++){ edge &e=G[st][i]; if(e.cap>0&&dis[st]<dis[e.to]){ int d=dfs(e.to,en,min(f,e.cap)); if(d>0){ e.cap-=d; G[e.to][e.rev].cap+=d; return d; } } } return 0; } int main(){ int n,a,b,c,m,sum,T,t=1; scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); for(int i=0;i<maxn;i++) G[i].clear(); sum=0; for(int i=1;i<=n;i++){ scanf("%d",&a);sum+=a; addedge(0,i,a); } for(int i=1;i<=m;i++){ scanf("%d",&num[i]); addedge(i+n,n+m+1,num[i]); } for(int i=1;i<=n;i++){ scanf("%d",&a); while(a--){ scanf("%d",&b);b++; addedge(i,b+n,inf); } } for(int i=1;i<=m;i++){ for(int j=1;j<=m;j++){ scanf("%d",&c); if(c) addedge(i+n,j+n,inf); } } int ans=0; while(1){ bfs(0); if(dis[n+m+1]<0) break; memset(iter,0,sizeof(iter)); int t; while((t=dfs(0,n+m+1,inf))) ans+=t; } printf("Case #%d: %d\n",t++,sum-ans); } return 0; }