(我真是越学越回去了,打回胎重造吧)
经典的最大权闭合子图模型,关键是怎么输出方案。用ISAP的话很显然需要额外搜一遍找出所有与S联通的点就是答案。
笔者第一眼居然以为判下流量就行 傻逼实锤
#include <bits/stdc++.h>
using namespace std;
const int N = 16384, MAXN = 262144;
#define reset(x) memset(x,0,sizeof x)
struct graph
{
int n,m,M,S,T,head[N],cur[N],dep[N],gap[N],q[N],vis[N];
long long ans;
struct ed
{
int to,nxt,val,src;
} edge[MAXN];
void init(int n0,int m0,int S0,int T0)
{
n=n0,m=m0,S=S0,T=T0,M=1,reset(gap);
reset(head),reset(cur),reset(dep),reset(q);
}
int _make(int u,int v,int w)
{
edge[++M]=(ed) {v,head[u],w,w},head[u]=M;
return M;
}
int make(int u,int v,int w)
{
_make(v,u,0);
return _make(u,v,w);
}
int dfs(int u,int mx)
{
if (u==T)
return mx;
int num=0,f;
for (int &i=cur[u],v; i; i=edge[i].nxt)
if (dep[v=edge[i].to]==dep[u]-1 && (f=edge[i].val))
if (edge[i].val-=(f=dfs(v,min(mx-num,f))), edge[i^1].val+=f, (num+=f)==mx)
return num;
if (!--gap[dep[u]++])
dep[S]=n+1;
return ++gap[dep[u]],cur[u]=head[u],num;
}
void _dfs(int p)
{
vis[p]=1;
if(p==T)
return;
for(int i=head[p]; i; i=edge[i].nxt)
{
int q=edge[i].to;
if(!vis[q] && edge[i].val)
_dfs(q);
}
}
void solve()
{
for (int i=1; i<=n; ++i)
cur[i]=head[i];
ans=0;
for (gap[0]=n; dep[S]<=n; ans+=dfs(S,0x7fffffff));
}
} g;
int n,m,t1,t2,t3,t4,tot,lab[100005],mac[100005];
char str[100005];
int main()
{
cin>>n>>m;
cin.getline(str,1e+5);
g.init(n+m+2,0,n+m+1,n+m+2);
for(int i=1; i<=n; i++)
{
cin.getline(str,1e+5);
stringstream ss(str);
ss>>t1;
tot+=t1;
lab[i] = g.make(n+m+1,i,t1);
while(ss>>t1)
{
g.make(i,n+t1,1e+9);
}
}
for(int i=1; i<=m; i++)
{
cin>>t1;
mac[i] = g.make(n+i,n+m+2,t1);
}
g.solve();
g._dfs(n+m+1);
int flag = 0;
for(int i=1; i<=n; i++)
{
if(g.vis[i])
{
if(flag)
cout<<" ";
flag=1;
cout<<i;
}
}
cout<<endl;
flag = 0;
for(int i=1; i<=m; i++)
{
if(g.vis[i+n])
{
if(flag)
cout<<" ";
flag=1;
cout<<i;
}
}
cout<<endl;
cout<<tot-g.ans<<endl;
}