[COGS 727]太空飞行计划
第一次做最大权闭合图……so sad
关于最大权闭合图的做法,可以参考胡伯涛前辈的《最小割模型在信息学竞赛中的应用》。不过很麻烦的事是……打印方案。
注意,割走的边要么和[tex]S[/tex]相连,要么就和[tex]T[/tex]相连。如果一条从[tex]S[/tex]到[tex]E_i[/tex]被割走了,那么就说明[tex]E_i[/tex]没有被选择;如果一条从[tex]I_i[/tex]到[tex]T[/tex]的边被割走了,那么就说明[tex]I_i[/tex]被选择了。
于是乎,Dinic最后一次造层次图的时候(这次最终将不能到达[tex]T[/tex]),如果某个点(除了[tex]S[/tex]和[tex]T[/tex])被访问到了,那个点就被选择了。
最小割的结果是所有拒绝的实验的能赚的钱及所有选用的仪器消耗的钱的和。也就是说,答案就是[tex]p[/tex]的和减去最小割。
代码:
#include <cstdio> #include <iostream> #include <iterator> #include <cstring> #include <string> #include <sstream> #include <vector> #include <queue> #include <algorithm> #include <bitset> using namespace std; const int maxn=211; const int INF=0x7fffffff; #define REP(i,n) for(i=0;i<(n);i++) #define REP_B(i,n) for(i=1;i<=(n);i++) #define CL_ARR(x,v) memset(x,v,sizeof(x)) struct Edge{ int u,v,cap,flow; }; namespace Dinic{ vector<Edge> edges; vector<int> G[maxn]; int m; inline void AddEdge(int u,int v,int cap){ edges.push_back((Edge){u,v,cap,0}); edges.push_back((Edge){v,u,0,0}); m=edges.size(); G[u].push_back(m-2); G[v].push_back(m-1); } bool vis[maxn]; int d[maxn],cur[maxn]; int s,t; inline bool BFS(){ register int i,u; queue<int> Q; CL_ARR(vis,0); Q.push(s); d[s]=0; vis[s]=true; while(!Q.empty()){ u=Q.front(); Q.pop(); REP(i,G[u].size()){ Edge& e=edges[G[u][i]]; if(!vis[e.v] && e.cap>e.flow){ vis[e.v]=1; d[e.v]=d[u]+1; Q.push(e.v); } } } return vis[t]; } int DFS(int x,int a){ if(x==t || a==0) return a; int flow=0,temp; for(int& i=cur[x];i<G[x].size();i++){ Edge& e=edges[G[x][i]]; if(d[e.v]==d[x]+1){ temp=DFS(e.v,min(a,e.cap-e.flow)); if(temp>0){ e.flow+=temp; edges[G[x][i]^1].flow-=temp; flow+=temp; a-=temp; if(a==0) break; } } } return flow; } inline int Mincut(int S,int T){ s=S; t=T; register int ans=0; while(BFS()){ CL_ARR(cur,0); ans+=DFS(s,INF); } return ans; } }; vector<int> AnsList; int main(){ register int i,j,ans=0; int m,n,p,x; bool flag; string line; // ios::sync_with_stdio(false); // cin.tie(0); freopen("shuttle.in","r",stdin); freopen("shuttle.out","w+",stdout); ostream_iterator<int> output(cout," "); scanf("%d %d\n",&m,&n); REP_B(i,m){ getline(cin,line); stringstream ss(line); ss>>p; ans+=p; Dinic::AddEdge(0,i,p); while(ss>>x){ Dinic::AddEdge(i,m+x,INF); } } REP_B(i,n){ cin>>p; Dinic::AddEdge(i+m,n+m+1,p); } ans-=Dinic::Mincut(0,n+m+1); REP_B(i,m){ if(Dinic::vis[i]){ AnsList.push_back(i); } } copy(AnsList.begin(),AnsList.end(),output); cout<<endl; AnsList.clear(); REP_B(i,n){ if(Dinic::vis[i+m]){ AnsList.push_back(i); } } copy(AnsList.begin(),AnsList.end(),output); cout<<endl; cout<<ans<<endl; return 0; }