题解:首先源点向每个实验建边,流量为经费的值,实验向器材建边,值为无限大,器材向终点建边,值为价值
然后跑一遍最大流就能跑出所谓的最大闭合图的点值之和.
代码如下:
#include<queue> #include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define hi puts("hi"); #define inf 0x3f3f3f3f using namespace std; int v[100010],w[100010],head[100010],next[100010],deep[100010],first[100010],cur[100010]; int n,m,s,t,cnt; void init() { cnt=-1; // memset(head,-1,sizeof(head)); memset(next,-1,sizeof(next)); } void add(int from,int to,int cost) { cnt++; next[cnt]=head[from]; // v[cnt]=to; w[cnt]=cost; head[from]=cnt; } void add_edge(int from,int to,int cost) { add(from,to,cost); add(to,from,0); } int bfs(int s,int t) { queue<int> q; memset(deep,0,sizeof(deep)); deep[s]=1; q.push(s); while(!q.empty()) { int u=q.front(); q.pop(); for(int i=head[u]; i!=-1; i=next[i]) { if(w[i]>0&&(!deep[v[i]])) { deep[v[i]]=deep[u]+1; q.push(v[i]); } } } if(!deep[t]) { return 0; } return 1; } int dfs(int u,int t,int dist) { if(u==t) { return dist; } for(int i=head[u]; i!=-1; i=next[i]) { if(w[i]&&(deep[v[i]]==deep[u]+1)) //!!! { int di=dfs(v[i],t,min(dist,w[i])); if(di>0) { w[i]-=di; w[i^1]+=di; return di; } } } return 0; } int dinic(int s,int t) { int ans=0; while(bfs(s,t)) { while(int d=dfs(s,t,inf)) { ans+=d; } } return ans; } int main() { init(); scanf("%d%d",&m,&n); int sum=0; s=0; t=n+m+1; int x; char c; for(int i=1; i<=m; i++) { scanf("%d",&x); sum+=x; add_edge(s,n+i,x); while(1) { scanf("%d%c",&x,&c); add_edge(n+i,x,inf); if(c==' '||c==' ') { break; } } } for(int i=1; i<=n; i++) { scanf("%d",&x); add_edge(i,t,x); } sum-=dinic(s,t); for(int i=1;i<=m;i++) { if(deep[i+n]) { printf("%d ",i); } } printf(" "); for(int i=1;i<=n;i++) { if(deep[i]) { printf("%d ",i); } } printf(" "); printf("%d ",sum); }