Description
有
Solution
實驗向所需儀器連邊,實驗的點權是其報酬,儀器的點權是其花費的相反數,這樣構成一張帶權圖。所求的就是這個圖的最大權閉合圖。
關於最大權閉合圖的求法及其證明,請參照胡澤濤的《最小割模型在信息學競賽中的應用》P16。
Code
//「網絡流 24 題」太空飛行計劃
#include <cstdio>
#include <cstring>
int const N=100+10;
int const INF=0x7FFFFFFF;
int m,n;
int s,t; int cnt,h[N];
struct edge{int v,c,nxt;} ed[N*N];
void edAdd(int u,int v,int c)
{
cnt++; ed[cnt].v=v,ed[cnt].c=c,ed[cnt].nxt=h[u],h[u]=cnt;
cnt++; ed[cnt].v=u,ed[cnt].c=0,ed[cnt].nxt=h[v],h[v]=cnt;
}
int dpt[N]; int op,cl,q[N];
bool bfs()
{
op=cl=0; memset(dpt,0,sizeof dpt);
dpt[q[++cl]=s]=1;
while(op<cl)
{
int u=q[++op]; if(u==t) break;
for(int i=h[u];i;i=ed[i].nxt)
{
int v=ed[i].v,c=ed[i].c;
if(!dpt[v]&&c) dpt[q[++cl]=v]=dpt[u]+1;
}
}
return dpt[t];
}
int min(int x,int y) {return x<y?x:y;}
int fill(int u,int in)
{
if(u==t||in==0) return in;
int out=0;
for(int i=h[u];i;i=ed[i].nxt)
{
int v=ed[i].v,c=ed[i].c;
if(dpt[v]!=dpt[u]+1||!c) continue;
int fl=fill(v,min(c,in-out));
if(!fl) dpt[v]=0;
else out+=fl,ed[i].c-=fl,ed[i^1].c+=fl;
if(in==out) return out;
}
return out;
}
int Dinic()
{
int ans=0;
while(bfs()) ans+=fill(s,INF);
return ans;
}
bool buy[N];
int main()
{
scanf("%d%d",&m,&n); s=0,t=n+m+1; cnt=1;
int ans=0;
for(int i=1;i<=m;i++)
{
int c=0; scanf("%d",&c);
ans+=c; edAdd(s,i,c);
while(true)
{
char ch=getchar(); if(ch=='\n'||ch=='\r') break;
int x; scanf("%d",&x); edAdd(i,m+x,INF);
}
}
for(int i=1;i<=n;i++) {int c; scanf("%d",&c); edAdd(m+i,t,c);}
ans-=Dinic();
for(int i=1;i<=m;i++) if(dpt[i]) printf("%d ",i); printf("\n");
for(int i=1;i<=n;i++) if(dpt[i+m]) printf("%d ",i); printf("\n");
printf("%d\n",ans);
return 0;
}
P.S.
又是鬼畜的輸入格式…