8/26 网络流Dinic算法+最小割+cf
Posted 钟钟终
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了8/26 网络流Dinic算法+最小割+cf相关的知识,希望对你有一定的参考价值。
Dinic算法相较于EK()算法效率更高
P3254 圆桌问题
思路:可用二分图来写,本题在于练习Dinic算法。
1.建立一个超级源点,连接每个代表团,权值为每个代表团的人数;
2.建立一个超级汇点,将每个圆桌连接汇点,权值为圆桌可容纳的人数;
3.将每个代表团连接每个圆桌,由于每个代表团不会安排两个人去同一个圆桌,因此权值都为1.
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
struct edge
int to,c,nxt;
e[N];
int n,m,r[N],c[N],s,t,sum;
int head[N],idx=1;
int d[N],cur[N];
void add(int a,int b,int c)
e[++idx]=b,c,head[a];
head[a]=idx;
bool bfs()
memset(d,0,sizeof d);
queue<int>q;
q.push(s);
d[s]=1;
while(q.size())
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(d[v]==0&&e[i].c)
d[v]=d[u]+1;
q.push(v);
if(v==t) return 1;
return 0;
int dfs(int u,int mf)
if(u==t) return mf;
int sum=0;
for(int i=cur[u];i;i=e[i].nxt)
cur[u]=i;
int v=e[i].to;
if(d[v]==d[u]+1&&e[i].c)
int f=dfs(v,min(mf,e[i].c));
e[i].c-=f;
e[i^1].c+=f;
sum+=f;
mf-=f;
if(mf==0) break;
if(sum==0) d[u]=0;
return sum;
int dinic()
int flow=0;
while(bfs())
memcpy(cur,head,sizeof head);
flow+=dfs(s,inf);
return flow;
void solve()
cin>>m>>n;
s=0,t=n+m+1;
for(int i=1;i<=m;i++)
cin>>r[i];sum+=r[i];
add(0,i,r[i]); //建立一个超级源点
add(i,0,0);
for(int i=1;i<=n;i++)
cin>>c[i];
add(i+m,t,c[i]);//建立一个超级汇点
add(t,i+m,0);
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
add(i,j+m,1);
add(j+m,i,0);
int ans=dinic();
if(ans!=sum)
cout<<0<<endl;
else
cout<<1<<endl;
for(int k=1;k<=m;k++)
for(int i=head[k];i;i=e[i].nxt)
if(e[i].to>m&&e[i].to<=m+n&&!e[i].c)
cout<<e[i].to-m<<" ";
cout<<endl;
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
最小割
大佬讲解:https://www.bilibili.com/video/BV1iG411s7iX?spm_id_from=333.999.0.0&vd_source=91973ada1213cf6ba2cbb43a2bebd2e8
最小割最大流定理:最小割的容量等于最大流的容量
P1344 [USACO4.4]追查坏牛奶Pollutant Control
三个问题:
最小割、最小割的划分、最小割的最少边数
代码:
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=7e5+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
struct edge
int to,c,nxt;
e[N];
int n,m,a[N],b[N],s,t;
int head[N],idx=1;
int d[N],cur[N];
void add(int a,int b,int c)
e[++idx]=b,c,head[a];
head[a]=idx;
bool bfs()
memset(d,0,sizeof d);
queue<int>q;
q.push(s);
d[s]=1;
while(q.size())
int u=q.front();q.pop();
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(d[v]==0&&e[i].c)
d[v]=d[u]+1;
q.push(v);
if(v==t) return 1;
return 0;
int dfs(int u,int mf)
if(u==t) return mf;
int sum=0;
for(int i=cur[u];i;i=e[i].nxt)
cur[u]=i;
int v=e[i].to;
if(d[v]==d[u]+1&&e[i].c)
int f=dfs(v,min(mf,e[i].c));
e[i].c-=f;
e[i^1].c+=f;
sum+=f;
mf-=f;
if(mf==0) break;
if(sum==0) d[u]=0;
return sum;
int dinic()
int flow=0;
while(bfs())
memcpy(cur,head,sizeof head);
flow+=dfs(s,inf);
return flow;
bool vis[N];
void mincut(int u)
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt)
int v=e[i].to;
if(!vis[v]&&e[i].c)
mincut(v);
void solve()
cin>>m>>n;
s=1,t=n;
for(int i=1,c;i<=m;i++)
cin>>a[i]>>b[i]>>c;
add(a[i],b[i],c);
add(b[i],a[i],0);
//最小割的容量
cout<<dinic()<<endl;
//最小割的划分
for(int i=1;i<=n;i++) // S
if(vis[i])
cout<<i<<" ";
for(int i=1;i<=n;i++) // T
if(!vis[i])
cout<<i<<" ";
//最小割最少边数
idx=1;
memset(head,0,sizeof head);
for(int i=1;i<=m;i++)
add(a[i],b[i],1);
add(b[i],a[i],0);
cout<<dinic()<<endl;
signed main()
//ios;
//int T;cin>>T;
//while(T--)
solve();
return 0;
C. Directional Increase
思路:
1.可通过加一移动到下一个元素,也可通过减1操纵移动到前一个元素,由于是从1开始,最后回到位置1,因此前缀和必定是>=0的。
2.在最后后一个非0元素由于要回到1,因此肯定为负数,前缀和肯定为0.
#include<bits/stdc++.h>
#define int long long
#define endl '\\n'
#define For(i,a,b) for(i=(a);i<=(b);++i)
#define ios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
using namespace std;
const int N=1e6+7;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n,a[N],sum[N];
void solve()
cin>>n;
for(int i=0;i<=n;i++)
sum[i]=0;
for(int i=1;i<=n;i++)
cin>>a[i];
for(int i=1;i<=n;i++)
sum[i]=sum[i-1]+a[i];
int flag=1,idx=1;
for(int i=n;i>=1;i--)
if(a[i])
idx=i;break;
if(sum[n]) flag=0;
for(int i=1;i<=n;i++)
if(sum[i]<=0&&i!=idx)
flag=0;break;
else if(i==idx)
break;
if(flag)
cout<<"Yes"<<endl;
else
cout<<"No"<<endl;
signed main()
//ios;
int T;cin>>T;
while(T--)
solve();
return 0;
D. Fake Plastic Trees
思路:
1.贪心思想,需要对每个叶子结点都操作一次,本条路径上所有经过的点都加上该值。
2.利用深搜,若大于r[u],则返回r[u];
以上是关于8/26 网络流Dinic算法+最小割+cf的主要内容,如果未能解决你的问题,请参考以下文章
网络流二·最大流最小割定理(Dinic模板+dfs/bfs找S集合模板)
POJ 3469(Dual Core CPU-最小割)[Template:网络流dinic V2]