P1361 小M的作物(最小割)

Posted Harris-H

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1361 小M的作物(最小割)相关的知识,希望对你有一定的参考价值。

P1361 小M的作物(最小割)

比较板子的题,关键是建图。

答案就是 s u m − sum- sum最小割。

而根据最小割最大流定理,即可求出最小割。

复习一下

Dinic 算法流程:

  • bfs给图分层,一次找多条增广路径

    • bool bfs(){
      	queue<int>q;q.push(st);mst(dep,0);dep[st]=1;//起点层数初始化为1,并入队列.
          
      	while(!q.empty()){
      		int u=q.front();q.pop();cur[u]=h[u];//弧优化初始化
      		for(int i=h[u];i;i=e[i].nt){
      			int v=e[i].to,w=e[i].w;
                  //如果当前还有剩余流量并且节点v未访问.
      			if(w&&!dep[v]) dep[v]=dep[u]+1,q.push(v);
      		}
      	}
      	return dep[ed];//如果终点被分层说明有增广路,否则没有.
      }
      
  • dfs进行增广路径计算。

    • int dfs(int u,int c){
      	if(u==ed) return c;
      	int res=c;
      	for(int &i=cur[u];i;i=e[i].nt){//弧优化
      		int v=e[i].to,w=e[i].w;
      		if(w&&dep[v]==dep[u]+1){
                  //如果当前结点v在增广路径上且还有流量.
      			int now=dfs(v,min(res,w));//暂存此时的贡献为now
      			if(!now) dep[v]=1;//如果流量为0说明该点已经没用了,走不了了,设置层数为1,避免重复访问.
      			else e[i].w-=now,e[i^1].w+=now,res-=now;
                  //否则修改边权,注意保证反悔性质,同时剩余流量减去.
      		}
      		if(!res) return c;//优化,如果剩余流量为0直接返回.
      	}
      	return c-res;//总流量-剩余流量=答案.
      }
      
  • 一直进行bfs,直到找不到增广路径为止。

    • ll dinic(){
      	ll s=0;
      	while(bfs()) s+=dfs(st,inf);
      	return s;
      }
      

code

// Problem: P1361 小M的作物
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1361
// Memory Limit: 125 MB
// Time Limit: 2000 ms
// Date: 2021-07-05 15:33:30
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=3e3+5,M=2e6+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define ios ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\\n",a[n]); 
}
int n,a[N],b[N],st,ed,tot;
struct edge{
	int to,nt,w;
}e[M];
int h[N],cur[N],cnt=1,dep[N];
void add(int u,int v,int w){
	e[++cnt]={v,h[u],w},h[u]=cnt;
	e[++cnt]={u,h[v],0},h[v]=cnt;
}
int dfs(int u,int c){
	if(u==ed) return c;
	int res=c;
	for(int &i=cur[u];i;i=e[i].nt){
		int v=e[i].to,w=e[i].w;
		if(w&&dep[v]==dep[u]+1){
			int now=dfs(v,min(res,w));
			if(!now) dep[v]=1;//如果剩余路径的最大流为0,说明该点不用再遍历了. 
			else e[i].w-=now,e[i^1].w+=now,res-=now;
		}
		if(!res) return c;//如果剩余流量为0,说明最大流不能再更大了,直接返回. 
	}return c-res;
} 
bool bfs(){
	queue<int>q;q.push(st);mst(dep,0),dep[st]=1;
	while(!q.empty()){
		int u=q.front();q.pop();cur[u]=h[u];//初始化 
		for(int i=h[u];i;i=e[i].nt){
			int v=e[i].to,w=e[i].w;
			if(w&&!dep[v]) dep[v]=dep[u]+1,q.push(v);
		}
	}return dep[ed];
} 
ll dinic(){
	ll s=0;
	while(bfs()) s+=dfs(st,inf);
	return s;
}
int main(){
	scanf("%d",&n);
	tot=n;
	st=0,ed=N-1;
	ll sum=0;
	for(int i=1;i<=n;i++) scanf("%d",&a[i]),add(st,i,a[i]),sum+=a[i];
	for(int i=1;i<=n;i++) scanf("%d",&b[i]),add(i,ed,b[i]),sum+=b[i];
	int m;scanf("%d",&m);
	for(int i=1;i<=m;i++){
		int x;scanf("%d",&x);
		int c1,c2;
		scanf("%d%d",&c1,&c2);
		sum+=c1+c2;
		add(st,++tot,c1);
		add(++tot,ed,c2);
		for(int j=1,y;j<=x;j++){
			scanf("%d",&y);
				add(tot-1,y,inf);
				add(y,tot,inf);
			}
	}
	printf("%lld\\n",sum-dinic());
	return 0;
}

以上是关于P1361 小M的作物(最小割)的主要内容,如果未能解决你的问题,请参考以下文章

P1361 小M的作物

3438: 小M的作物[最小割]

luogu P1361 小M的作物 |网络流

luogu P1361 小M的作物 |网络流

BZOJ3438 小M的作物(最小割)

BZOJ-3438小M的作物 最小割 + 最大权闭合图