CF1082G Petya and Graph

题目传送门

一道最大权闭合子图的模板题

把所有点当作负权点,所有边当作正权点。

考虑一条边 e=(x,y,z) 能选择的条件,当 x,y 均被选择时就可以选,那对应到最大权闭合子图的模型中,就可以将 (e,x),(e,y) 当作原图中的边。从 ex,y 连一条容量为 + 的边

建模完毕后用计算最大权闭合子图点权和即可

#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;
}
posted @   xishanmeigao  阅读(5)  评论(0编辑  收藏  举报
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?
点击右上角即可分享
微信分享提示