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的作物(最小割)的主要内容,如果未能解决你的问题,请参考以下文章