网络流(Dinic)

Dinic详解与实现
(https://www.cnblogs.com/LUO77/p/6115057.html)
(ISAP待留)

struct Dinic
{
    int c;//cap
    int f;//flow
}edge[205][205];//i:from; j:to

构造分层网络(level标号)

bool dinic_bfs()//建网
{
 queue<int>q;
 memset(level,0,sizeof(level));
 q.push(1);
 level[1]=1;
 int u,v;
 while(!q.empty)
 {
  u=q.front();
  q.pop();
  for(v=1;v<=E;v++)//
   if(!level[v]&&edge[u][v].c>edge[u][v].f)
   {
    level[v]=level[u]+1;
    q.push(v); 
   }
 }
 return level[E];//判断E点是否在网络内
}

进行增广

int dinic_dfs(int u,int cp)//进行增广 
{
 int tmp=cp;
 int v,t;
 if(u==E)//退回原点,增广结束 
  return cp;
 for(v=1;v<=E&&tmp;v++)
  if(level[u]+1==level[v]&&edge[u][v].c>edge[u][v].f)//符合增广条件 
  {
   t=dinic_dfs(v,min(tmp,edge[u][v].c-edge[u][v].f))//重点理解 
   edge[u][v].f+=t;//前 
   edge[v][u].f-=t;// 逆 
   tmp-=t;// 
  }
 return cp-tmp;//tmp减少的总量即增加的流量 
}

Dinic主思路

int dinic()
{
 int sum=0,tf=0;
 while(dinic_bfs())//判断是否可构造层次网络 
 {
  while(tf=dinic_dfs(1,INF))//进行增广 
   sum+=tf;
 }
 return sum;
}

但即便知道了最基本的思路,遇到实际问题依旧很难解决,所以需要对应题目的训练
基本版子
详解来源(https://www.cnblogs.com/TreeDream/p/5866347.html)

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
const int INF=0x3f3f3f3f;
const int maxn=505;
struct Edge{
 int from;int to;int cap;int flow;
};
struct Dinic{
 int n,m,s,t;
 vector<Edge>edge;vector<int>G[maxn];
 int level[maxn],cur[maxn];bool vis[maxn];
 void addEdge(int from,int to,int cap)
 {
  edge.push_back((Edge){from,to,cap,0});
  edge.push_back((Edge){to,from,0,0});
  int m=edge.size();
  G[from].push_back(m-2);
  G[to].push_back(m-1);
 } 
 bool BFS()
 {
  memset(vis,0,sizeof(vis));
  queue<int>Q;
  Q.push(s);level[s]=0;vis[s]=1;
  while(!Q.empty())
  {
   int x=Q.front();Q.pop();
   for(int i=0;i<G[x].size();i++)
   {
    Edge&e=edge[G[x][i]];
  if(!vis[e.to]&&e.cap>e.flow)
  {
   vis[e.to]=1;level[e.to]=level[x]+1;Q.push(e.to); 
  } 
 }
  }
  return vis[t];
 }
 int DFS(int x,int a)
 {
  if(x==t||a==0) return a;
  int flow=0,f;
  for(int &i=cur[x];i<G[x].size();i++)
  {
    Edge&e=edge[G[x][i]];
    if(level[e.to]==level[x]+1&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)
    {
     e.flow+=f;edge[G[x][i]^1].flow-=f;flow+=f;a-=f;if(a==0) break; 
  }
  
 }
 return flow;
 }
 int Maxflow(int s,int t)
 {
  this->s=s;this->t=t;
  int flow=0;
  while(BFS())
  {
   memset(cur,0,sizeof(cur));
  flow+=DFS(s,INF); 
 }
 return flow;
 }
}sol;
int main()
{
 int n,m;
 cin>>n>>m;
 for(int i=0;i<m;i++)
 {
  int u,v,cap;
  cin>>u>>v>>cap;
  sol.addEdge(u,v,cap);
 }
 cout<<sol.Maxflow(1,n)<<endl;
 return 0;
}

1:最大权闭合子集:http://www.cnblogs.com/TreeDream/p/5942354.html#_label0
可视作二分图 序偶(A R B) 变为闭合子集,后用网络流求解

#include<iostream>
#include<cstring>
#include<cstring>
#include<queue> 
using namespace std;
#define maxn 505
#define INF 0x3f3f3f3f
struct Edge//边 
{
 int from,to,cap,flow;
};
struct Dinic
{
 int n,m,s,t;
 vector<Edge>edge;//边 
 vector<int> G[maxn];//闭合子集 
 bool vis[maxn];//分层 标记 
 int d[maxn];//?
 int cur[maxn];//?
 void init()//输入前赋初值操作 
 {
  for(int i=0;i<maxn;i++)
  G[i].clear();
 edge.clear();// queue清空用 clear
 memset(d,0,sizeof(d));
 memset(vis,0,sizeof(vis));
 memset(cur,0,sizeof(cur)); 
 }
 void addEdge(int from,int to,int cap)//建边 
 {
  edge.push_back((Edge){from,to,cap,0});//建正边
  edge.push_back((Edge){to,from,0,0});//建逆边
  m=edge.size();//?
  G[from].push_back(m-2);//?
  G[to].push_back(m-1); //?
 }
 bool BFS()//建分层网络 
 { 
  memset(vis,0,sizeof(vis));
  queue<int>Q;
  Q.push(s);
  d[s]=0;
  vis[s]=1;
  while(!Q.empty())
  {
   int x=Q.front();
   Q.pop();
   for(int i=0;i<G[x].size();i++)
   {
    Edge &e=edge[G[x][i]];
 if(!vis[e.to]&&e.cap>e.flow)//日常两个条件 
 {
  vis[e.to]=1;
  d[e.to]=d[x]+1;
  Q.push(e.to); 
 } 
   } 
  } 
  return vis[t];//汇点在图里; 
 }
 long long DFS(int x,int a)
 {
  if(x==t||a==0) return a;//增广到最后一点返回 
  long long flow=0,f;
  for(int &i=cur[x];i<G[x].size();i++) 
  {
   Edge&e=edge[G[x][i]];
   if(d[x]+1==d[e.to]&&(f=DFS(e.to,min(a,e.cap-e.flow)))>0)//
   {
     e.flow+=f;
  edge[G[x][i]^1].flow-=f;
  flow+=f;
  a-=f;
  if(a==0) break; 
 }
  }
  return flow;
 }
 int Maxflow(int s,int t)
 {
  this->s=s;this->t=t;
  int flow=0;
  while(BFS())
  {
   memset(cur,0,sizeof(cur));
   flow+=DFS(s,INF);
  }
  return flow;
 } 
 //求最小割S,T
 void new_BFS(int s,int n)
 {
  memset(vis,0,sizeof(vis));
  d[s]=0;
  vis[s]=1;
  queue<int>Q;
  Q.push(s);
  while(!Q.empty())
  {
   int u=Q.front();
   Q.pop();
   for(int i=0;i<G[u].size();i++)
   {
    Edge&e= edge[G[u][i]];
 if(!vis[e.to]&&e.cap>e.flow)
 {
  vis[e.to]=1;
  d[e.to]=d[u]+1;
  Q.push(e.to); 
 } 
   } 
  } 
  int cnt=0;
  for(int i=1;i<=n;i++)
   if(vis[i])
    cnt++;
  cout<<cnt<<endl;
  for(int i=1;i<=n;i++)
   if(vis[i])
    cout<<i<<" ";
  puts("");
 } 
}sol;
int main()
{
 sol.init();//??
 int n,m;//n活动,m人 
 cin>>n>>m;
 int s=0;//源点 
 int t=n+m+1;//汇点 
 int cap;
 for(int i=1;i<=m;i++)
 {
  cin>>cap;//人消耗的活跃度 
  sol.addEdge(n+i,t,cap);//建边,负权边联接到汇点t 
 } 
 int sum=0;
 for(int i=1;i<=n;i++)
 {
  int a,k;
  sum+=a;//活动产生的总活跃度
 sol.addEdge(s,i,a);// 建边,正权边连接到源点s
 for(int j=0;j<k;j++)//A到B间建立关系,赋值无穷 
 {
  int v;
  cin>>v;
  sol.addEdge(i,v+n,INF); 
 } 
 }
 cout<<sum-sol.Maxflow(s,t)<<endl;//最大权闭合子图=正点和-最小割。
 return 0; 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值