CF1082G Petya and Graph
(题目传送门)
一道最大权闭合子图的模板题
把所有点当作负权点,所有边当作正权点。
考虑一条边 \(e=(x,y,z)\) 能选择的条件,当 \(x,y\) 均被选择时就可以选,那对应到最大权闭合子图的模型中,就可以将 \((e,x),(e,y)\) 当作原图中的边。从 \(e\rightarrow x,y\) 连一条容量为 \(+\infty\) 的边
建模完毕后用计算最大权闭合子图点权和即可
#include<bits/stdc++.h>
using namespace std;
const int N=55010,M=65010,INF=1e9;
int n,m,s,t,d[N],maxflow,sum;
int head[N],ver[2*M],nxt[2*M],edge[2*M],now[N],tot=1;
void add(int x,int y,int z)
{
ver[++tot]=y; edge[tot]=z; nxt[tot]=head[x]; head[x]=tot;
ver[++tot]=x; edge[tot]=0; nxt[tot]=head[y]; head[y]=tot;
}
bool bfs()
{
memset(d,0,sizeof(d));
queue <int> q;
d[s]=1; q.push(s);
now[s]=head[s];
while(q.size())
{
int x=q.front(); q.pop();
for(int i=head[x]; i; i=nxt[i])
{
if(edge[i] && !d[ver[i]])
{
int y=ver[i];
d[y]=d[x]+1;
now[y]=head[y];
if(y==t)
return 1;
q.push(y);
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x==t)
return flow;
int rest=flow,k;
for(int &i=now[x]; i && rest; i=nxt[i])
{
if(edge[i] && d[ver[i]]==d[x]+1)
{
int y=ver[i];
k=dinic(y,min(rest,edge[i]));
if(!k)
d[y]=0;
edge[i]-=k;
edge[i^1]+=k;
rest-=k;
if(rest<=0)
break;
}
}
return flow-rest;
}
int Dinic()
{
int flow=0;
while(bfs())
while(flow=dinic(s,INF))
maxflow+=flow;
return maxflow;
}
int main()
{
scanf("%d%d",&n,&m);
s=0; t=n+m+1;
for(int i=1; i<=n; i++)
{
int x;
scanf("%d",&x);
add(i,t,x); //负点权点向汇点连边
}
for(int i=1; i<=m; i++)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
sum+=z;
add(s,i+n,z); //源点向正点权点连边
add(i+n,x,INF); add(i+n,y,INF); //e(即i+n)向x,y连边
}
printf("%d",sum-Dinic()); //正点权和-最小割
return 0;
}

浙公网安备 33010602011771号