题意:给了n个工程,m种技术,完成某些工程可能需要先学习某些技术,完成一个工程可以得到该工程的收益,学习一种技术也要付出一定的花费,求最大收益,并且某种技术的学习可能需要先学另一种技术,并且可以相互需要,如果是相互需要则两种技术要同时学习
思路:由于技术与技术之间可能相互都有边,所以就可能存在环,可以先用强连通分量缩点,然后就可以当做DAG图来处理了,最后就可以转换为网络流模型,首先源点与各个工程之间连边,流量为该工程的收益,然后各个技术与汇点连边,流量为学习该技术的花费,然后是技术与技术之间,如果学习技术 i 要先学习技术 j,则从 i 向 j 连边,流量为正无穷,最后是工程与技术之间,若工程 i 需要技术 j ,则从 i 想 j 连边,流量为该工程的收益,跑一遍最大流,答案为所有工程的总收益减最大流
ps:不缩点也可以,有环对最大权闭合图的求解没有影响
#include<iostream>
#include<string>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<iomanip>
#include<map>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#define inf 1000000000
#define pi acos(-1.0)
#define eps 1e-8
#define seed 131
using namespace std;
typedef pair<int,int> pii;
typedef unsigned long long ull;
typedef long long ll;
const int maxn=100;
int n,m;
int s,t;
int val[25];
vector<int>need[25];
int cost[55];
int newcost[55];
bool mp[55][55];
struct Tarjan
{
vector<int>g[55];
int dfn[55],low[55],sccno[55],dfs_clock,scc_cnt;
stack<int>s;
void dfs(int u)
{
dfn[u]=low[u]=++dfs_clock;
s.push(u);
for(int i=0;i<g[u].size();i++)
{
int v=g[u][i];
if(!dfn[v])
{
dfs(v);
low[u]=min(low[u],low[v]);
}
else if(!sccno[v])
low[u]=min(low[u],dfn[v]);
}
if(low[u]==dfn[u])
{
scc_cnt++;
while(1)
{
int x=s.top();
s.pop();
sccno[x]=scc_cnt;
if(x==u)
break;
}
}
}
void find_scc(int n)
{
dfs_clock=scc_cnt=0;
memset(sccno,0,sizeof(sccno));
memset(dfn,0,sizeof(dfn));
while(!s.empty())
s.pop();
for(int i=1;i<=n;i++)
if(!dfn[i])
dfs(i);
}
void init(int n)
{
for(int i=1;i<=n;i++)
g[i].clear();
}
}suo;
struct Edge
{
int from,to,cap,flow;
Edge(int a,int b,int c,int d):from(a),to(b),cap(c),flow(d){}
};
struct Dinic
{
vector<Edge>edges;
vector<int>G[maxn];
bool vis[maxn];
int d[maxn];
int cur[maxn];
void init(int u)
{
for(int i=1;i<=u;i++)
G[i].clear();
edges.clear();
}
void add(int u,int v,int flow)
{
edges.push_back(Edge(u,v,flow,0));
edges.push_back(Edge(v,u,0,0));
G[u].push_back(edges.size()-2);
G[v].push_back(edges.size()-1);
}
bool BFS()
{
memset(vis,0,sizeof(vis));
queue<int>Q;
Q.push(s);
d[s]=0;
vis[s]=1;
while(!Q.empty())
{
int x=Q.front();
Q.pop();
for(int i=0;i<G[x].size();i++)
{
Edge& e=edges[G[x][i]];
if(!vis[e.to]&&e.cap>e.flow)
{
vis[e.to]=1;
d[e.to]=d[x]+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[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
{
e.flow+=f;
edges[G[x][i]^1].flow-=f;
flow+=f;
a-=f;
if(a==0)
break;
}
}
return flow;
}
int Maxflow(int s,int t)
{
int flow=0;
while(BFS())
{
memset(cur,0,sizeof(cur));
flow+=DFS(s,inf);
}
return flow;
}
}fp;
int main()
{
int tt;
scanf("%d",&tt);
int a;
int tot;
int cas=1;
while(tt--)
{
tot=0;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&val[i]);
tot+=val[i];
need[i].clear();
}
for(int i=1;i<=m;i++)
scanf("%d",&cost[i]);
for(int i=1;i<=n;i++)
{
int num;
scanf("%d",&num);
for(int j=0;j<num;j++)
{
scanf("%d",&a);
need[i].push_back(a+1);
}
}
suo.init(m);
for(int i=1;i<=m;i++)
{
for(int j=1;j<=m;j++)
{
scanf("%d",&mp[i][j]);
if(mp[i][j]==1)
suo.g[i].push_back(j);
}
}
memset(newcost,0,sizeof(newcost));
suo.find_scc(m);
for(int i=1;i<=m;i++)
{
newcost[suo.sccno[i]]+=cost[i];
}
int mm=m;
m=suo.scc_cnt;
s=n+m+1,t=n+m+2;
fp.init(n+m+2);
for(int i=1;i<=n;i++)
{
fp.add(s,i,val[i]);
vector<int>newneed;
for(int j=0;j<need[i].size();j++)
newneed.push_back(suo.sccno[need[i][j]]);
sort(newneed.begin(),newneed.end());
int nm=unique(newneed.begin(),newneed.end())-newneed.begin();
for(int j=0;j<nm;j++)
fp.add(i,newneed[j]+n,inf);
}
for(int i=1;i<=m;i++)
fp.add(n+i,t,newcost[i]);
for(int i=1;i<=mm;i++)
{
for(int j=1;j<=mm;j++)
{
if(mp[i][j]==1)
{
if(suo.sccno[i]!=suo.sccno[j])
fp.add(suo.sccno[i]+n,suo.sccno[j]+n,inf);
}
}
}
printf("Case #%d: %d\n",cas++,tot-fp.Maxflow(s,t));
}
return 0;
}