其他分享
首页 > 其他分享> > 图论 网络流 lgP4001题解

图论 网络流 lgP4001题解

作者:互联网

题目大意

给定一张无向图,需要消耗代价才能使一条边被【数据删除】,求使这张图不连通的最小代价。

一看就是最小割的应用啊。。。

从 \(u\) 到 \(v\),边权为 \(w\) 的边,建两条:一条从 \(u\) 到 \(v\) ,边权为 \(w\),另一条从 \(v\) 到 \(u\),边权也为 \(w\)。

然后直接跑 \(\rm Dinic\) 就行了qwq。

code:

#include<cstring>
#include<cstdio>
#include<queue> 
const int M=1e6+5;
struct Edge{
	int to,nx,flow;
}e[M<<4];
int n,m,s,t,cnt,d[M],h[M],sur[M],id[1005][1005];
inline void Add(int x,int y,int flow){
	e[++cnt]=(Edge){y,h[x],flow};h[x]=cnt;
}
inline int min(const int x,const int y){
	return x>y?y:x;
}
inline bool BFS()
{
	std::queue<int>q;
	memset(d,0,(n*m+1)<<2);
	d[s]=1;q.push(s);
	while(!q.empty()){
		int u=q.front();q.pop();
		for(int E=h[u];E;E=e[E].nx)if(e[E].flow){
			int v=e[E].to;
			if(!d[v]){
				d[v]=d[u]+1;
				q.push(v);
			}	
		}
	}
	return d[t];
}
inline int DFS(int u,int flow)
{
	if(u==t)return flow;
	int used=flow;
	for(int&E=sur[u];E;E=e[E].nx)if(e[E].flow){
		int v=e[E].to;
		if(d[u]+1==d[v])
		{
			int f=DFS(v,min(used,e[E].flow));
			e[E].flow-=f,e[E^1].flow+=f;used-=f;
			if(!f)d[v]=0;if(!used)return flow;
		}
	}
	return flow-used;
}
signed main(){
	int i,j,ans=0,flow;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)for(j=1;j<=m;++j)id[i][j]=++cnt;
	cnt=1;s=id[1][1];t=id[n][m];
	for(i=1;i<=n;++i)for(j=1;j<m;++j){
		int&x=id[i][j],&y=id[i][j+1];
		scanf("%d",&flow);
		Add(x,y,flow);Add(y,x,0);
		Add(y,x,flow);Add(x,y,0);
	}
	for(i=1;i<n;++i)for(j=1;j<=m;++j){
		int&x=id[i][j],&y=id[i+1][j];
		scanf("%d",&flow);
		Add(x,y,flow);Add(y,x,0);
		Add(y,x,flow);Add(x,y,0);
	}
	for(i=1;i<n;++i)for(j=1;j<m;++j){
		int&x=id[i][j],&y=id[i+1][j+1];
		scanf("%d",&flow);
		Add(x,y,flow);Add(y,x,0);
		Add(y,x,flow);Add(x,y,0);
	}
	while(BFS()){
		for(int u=1;u<=n*m;++u)sur[u]=h[u];
		while(int flow=DFS(s,2e9))ans+=flow;
	}
	printf("%d",ans);
}

标签:图论,一条,int,题解,边权,最小,lgP4001,include,代价
来源: https://www.cnblogs.com/lmpp/p/15784589.html