2022/1/19
2022/1/19
网络流练习&&模板
[P3376 【模板】网络最大流]( P3376 [模板]网络最大流 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) )
参考代码
#include
#define ll long long
#define pii pair
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)
#define fi first
#define se second
#define watch(x) std::cout << (#x) << " is " << (x) << std::endl
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}
const int qs=8192*2;
const ll mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll n,m,s,t;
ll head[qs],nxt[qs],to[qs];
ll dis[qs];
ll p;
void add(int fx,int tx,ll dx){
to[p]=tx;
dis[p]=dx;
nxt[p]=head[fx];
head[fx]=p++;
}
//Dinic
ll level[qs],cur[qs];
//level是各点到终点的深度,cur为当前弧优化的增广起点
bool bfs(){//分层图
memset(level,-1,sizeof(level));
level[s]=0;
memcpy(cur,head,sizeof(head));
cur[s]=head[s];
queue Q;
Q.push(s);
while(Q.si){
int k=Q.front();
Q.pop();
for(int i=head[k];i!=-1;i=nxt[i]){
if(dis[i]>0&&level[to[i]]==-1){
level[to[i]]=level[k]+1;
Q.push(to[i]);
if(to[i]==t) return true;
}
}
}
return false;
}
ll dfs(int u,ll flow){
if(u==t) return flow;
ll ret=flow; //剩余的流量
for(int i=cur[u];i!=-1&&ret>0;i=nxt[i]){
cur[u]=i;// 当前弧优化
//如果还能流下去 并且 更深
if(dis[i]>0&&level[to[i]]==level[u]+1){
ll c=dfs(to[i],min(dis[i],ret));
if(!c) level[to[i]]=-1; //剪枝,出去增广完毕的点
ret-=c; //剩余的水流被用了c
dis[i]-=c; //减权重
dis[i^1]+=c; //反向边加权重
}
}
return flow-ret;//返回用掉的水流
}
//END
int main(){
memset(head,-1,sizeof(head));
cin>>n>>m>>s>>t;
ll x,y,z;
while(m--){
cin>>x>>y>>z;
add(x,y,z);
add(y,x,0);// 反向边
//第一条边的序号是0,反向边是1
}
ll ans=0;
while(bfs()){
ans+=dfs(s,inf);
}
cout<
[ Dining ]( Dining (nowcoder.com) )
思路
考虑网络流(源点-食物-牛-饮料-汇点)建模,要保证一个牛只吃一种食物和一种饮料,
- 从源点s向食物做流量为1的边。
- 根据牛想吃的食物,从食物向牛连一条流量为1的边
- 从牛向饮料连一条流量为1的边
- 从饮料向汇点连一条流量为1的边
这样建出来的图不能保证一个牛只吃一种食物和饮料,因为增光路保证边不重复,但点可以经过多次,故还要牛向本身连一条流量为1的边。
参考代码
#include
#define ll long long
#define pii pair
#define se second
#define pb push_back
#define pf push_front
#define si size()
#define db double
#define ls (p<<1)
#define rs (p<<1|1)
#define fi first
#define se second
#define watch(x) std::cout << (#x) << " is " << (x) << std::endl
using namespace std;
ll read(){ll x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return x*f;}
inline void Prin(ll x){if(x < 0){putchar('-');x = -x;}if(x > 9) Prin(x / 10);putchar(x % 10 + '0');}
const int qs=8192*2;
const ll mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll N,F,D,s,t;
ll head[qs],nxt[qs],to[qs];
ll dis[qs];
ll p;
map mp;
void add(int fx,int tx,ll dx){
to[p]=tx;
dis[p]=dx;
nxt[p]=head[fx];
head[fx]=p++;
to[p]=fx;
dis[p]=0;
nxt[p]=head[tx];
head[tx]=p++;
}
//Dinic
ll level[qs],cur[qs];
//level是各点到终点的深度,cur为当前弧优化的增广起点
bool bfs(){//分层图
memset(level,-1,sizeof(level));
level[s]=0;
memcpy(cur,head,sizeof(head));
cur[s]=head[s];
queue Q;
Q.push(s);
while(Q.si){
int k=Q.front();
Q.pop();
for(int i=head[k];i!=-1;i=nxt[i]){
if(dis[i]>0&&level[to[i]]==-1){
level[to[i]]=level[k]+1;
Q.push(to[i]);
if(to[i]==t) return true;
}
}
}
return false;
}
ll dfs(int u,ll flow){
if(u==t) return flow;
ll ret=flow; //剩余的流量
for(int i=cur[u];i!=-1&&ret>0;i=nxt[i]){
cur[u]=i;// 当前弧优化
//如果还能流下去 并且 更深
if(dis[i]>0&&level[to[i]]==level[u]+1){
ll c=dfs(to[i],min(dis[i],ret));
if(!c) level[to[i]]=-1; //剪枝,出去增广完毕的点
ret-=c; //剩余的水流被用了c
dis[i]-=c; //减权重
dis[i^1]+=c; //反向边加权重
}
}
return flow-ret;//返回用掉的水流
}
//END
int main(){
memset(head,-1,sizeof(head));
N=read(),F=read(),D=read();
s=0,t=N+F*2+D+1;
for(int i=1;i<=F;++i) add(s,i,1);
for(int i=1;i<=N;++i) add(F+i,N+F+i,1);
for(int i=1;i<=D;++i) add(F+N*2+i,t,1);
ll Fi,Di,x;
for(int Ni=1;Ni<=N;++Ni){
Fi=read(),Di=read();
for(int i=1;i<=Fi;++i){
x=read();
add(x,F+Ni,1);
}
for(int i=1;i<=Di;++i){
x=read();
add(N+F+Ni,x+F+N*2,1);
}
}
ll ans=0;
while(bfs()){
ans+=dfs(s,inf);
}
cout<