思路:
最大權閉合圖中的權=原圖中權值爲正的點的和 - 最小割(最大流)
原圖就是權在點上,且權有正負,如樣例的原圖爲:
把點權圖轉化一下:
對這個圖跑最小割(最大流),就可以得到最大權閉合圖中的權了。
最後需要輸出方案,其實就是和源點相連的點,和匯點相連的點。
這題輸入有個奇怪,抄了別人的讀入。
參考代碼:
#include <bits/stdc++.h>
using namespace std;
const int N=505;
const int MAXN = 1<<26;
struct Edge{
int u,v,c;
int nxt;
}edge[N*N];
int n,m;
int head[N],edn;
int d[N];
int sp,tp;
void add_edge(int u,int v,int c)
{
edge[edn].u=u; edge[edn].v=v; edge[edn].c=c;
edge[edn].nxt=head[u]; head[u]=edn++;
edge[edn].u=v; edge[edn].v=u; edge[edn].c=0;
edge[edn].nxt=head[v]; head[v]=edn++;
}
int bfs()
{
queue <int> q;
memset(d,-1,sizeof(d));
d[sp]=0;
q.push(sp);
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=head[cur];i!=-1;i=edge[i].nxt)
{
int v=edge[i].v;
if(d[v]==-1 && edge[i].c>0)
{
d[v]=d[cur]+1;
q.push(v);
}
}
}
return d[tp] != -1;
}
int dfs(int a,int b)
{
int r=0;
if(a==tp)return b;
for(int i=head[a];i!=-1 && r<b;i=edge[i].nxt)
{
int v=edge[i].v;
if(edge[i].c>0 && d[v]==d[a]+1)
{
int x=min(edge[i].c,b-r);
x=dfs(v,x);
r+=x;
edge[i].c-=x;
edge[i^1].c+=x;
}
}
if(!r)d[a]=-2;
return r;
}
int dinic(int sp,int tp)
{
int total=0,t;
while(bfs())
{
while(t=dfs(sp,MAXN))
total+=t;
}
return total;
}
inline int read(int &x){
char c;x=0;
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return c=='\r'||c=='\n'?0:1;
}
int main(){
read(m),read(n);
memset(head,-1, sizeof(head));
edn=0;
int all=0;
sp=200,tp=201;
int flag;
for (int i=1,x;i<=m;i++)
{
flag=read(x);all+=x;
add_edge(sp,i,x);
while (flag){
flag=read(x);
add_edge(i,x+m,MAXN);
}
}
for(int i=m+1,x;i<=n+m;i++){
read(x);
add_edge(i,tp,x);
}
int tmp=dinic(sp,tp);
for(int i=1;i<=m;i++){
if(d[i]!=-1){
printf("%d ",i);
}
}
printf("\n");
for(int i=1;i<=n;i++){
if(d[m+i]!=-1){
printf("%d ",i);
}
}
printf("\n%d\n",all-tmp);
return 0;
}