题目大意:有两家公司都想向政府申请某些资源的使用权,并且他们都提供了一些申请列表,列表中含有申请费用和资源种类,同一家公司的申请列表之间不含有重复的资源。政府只可以完整地接受和拒绝谋一份申请列表,问政府的最大收益是多少。
题目分析:如果两家公司的申请之间没有任何矛盾,那么最大的收益就是所有的申请费用之和。如果某些列表之间有矛盾,那么就需要用最小的代价使两家公司的申请没有任何矛盾。将每一条申请视作一个点,增加源点s和汇点t,从s向甲公司的每一条申请连一条弧,容量为该申请的费用;从乙公司的每一条申请向t连一条弧,容量为每条申请对应的费用;然后对于甲公司的每一条申请,向所有与它矛盾的申请(只可能是乙公司的申请)连一条弧,容量为无穷大。那么,最小割便是这个最小代价,用申请费用总和减去最小代价便是最大收益。
代码如下:
# include<iostream> # include<cstdio> # include<cmath> # include<string> # include<vector> # include<list> # include<set> # include<map> # include<queue> # include<cstring> # include<algorithm> using namespace std; # define LL long long # define REP(i,s,n) for(int i=s;i<n;++i) # define CL(a,b) memset(a,b,sizeof(a)) # define CLL(a,b,n) fill(a,a+n,b) const double inf=1e30; const int INF=1<<30; const int N=6005; ///////////////////////////////// struct Edge { int fr,to,cap,fw; Edge(int _fr,int _to,int _cap,int _fw):fr(_fr),to(_to),cap(_cap),fw(_fw){} }; struct Dinic{ vector<Edge>edges; vector<int>G[N]; int d[N],vis[N],cur[N]; int s,t; void init(int n,int s,int t) { this->s=0,this->t=t; REP(i,0,n) G[i].clear(); edges.size(); } void addEdge(int u,int v,int cap) { edges.push_back(Edge(u,v,cap,0)); edges.push_back(Edge(v,u,0,0)); int len=edges.size(); G[u].push_back(len-2); G[v].push_back(len-1); } bool BFS() { CL(vis,0); d[s]=0; vis[s]=1; queue<int>q; q.push(s); while(!q.empty()){ int x=q.front(); q.pop(); REP(i,0,G[x].size()){ Edge &e=edges[G[x][i]]; if(!vis[e.to]&&e.cap>e.fw){ d[e.to]=d[x]+1; vis[e.to]=1; q.push(e.to); } } } return vis[t]; } int DFS(int x,int a) { if(x==t||a==0) return a; int flow=0,f; for(int &i=cur[x];i<G[x].size();++i){ Edge &e=edges[G[x][i]]; if(d[e.to]==d[x]+1&&(f=DFS(e.to,min(a,e.cap-e.fw)))>0){ e.fw+=f; edges[G[x][i]^1].fw-=f; flow+=f; a-=f; if(a==0) break; } } return flow; } int MaxFlow() { int flow=0; while(BFS()){ CL(cur,0); flow+=DFS(s,INF); } return flow; } }; Dinic dinic; //////////////////////////////////// int sum,maxn; int a[300005],b[300005]; bool vis[3005][3005]; int p1[3005],p2[3005]; void init() { maxn=sum=0; CL(a,0); CL(b,0); } bool read(int &x) { x=0; char c; while(c=getchar()){ if(c==' ') return false; if(c==' ') return true; x=x*10+c-'0'; } } int main() { int T,n,m,cas=0; scanf("%d",&T); while(T--) { init(); scanf("%d",&n); REP(i,1,n+1){ scanf("%d",&p1[i]); sum+=p1[i]; int x; getchar(); while(read(x)) { a[x]=i; maxn=max(maxn,x); } a[x]=i; maxn=max(maxn,x); } scanf("%d",&m); dinic.s=0,dinic.t=n+m+1; REP(i,1,m+1){ scanf("%d",&p2[i]); sum+=p2[i]; int x; while(read(x)) { b[x]=i; maxn=max(maxn,x); } b[x]=i; maxn=max(maxn,x); } dinic.init(n+m+2,0,n+m+1); REP(i,1,n+1) dinic.addEdge(0,i,p1[i]); REP(i,1,m+1) dinic.addEdge(i+n,n+m+1,p2[i]); CL(vis,false); REP(i,1,maxn+1){ if(!a[i]||!b[i]||vis[a[i]][b[i]]) continue; vis[a[i]][b[i]]=true; dinic.addEdge(a[i],b[i]+n,INF); } printf("Case %d: ",++cas); printf("%d ",sum-dinic.MaxFlow()); if(T) printf(" "); } return 0; }