关于网络流算法

Posted

tags:

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

实现MCMF的基础上进行尝试针对题目修改代码就方便许多,这里的一个难点是如何输出MCMF对应的各条流路径(网络路径)。实现了MCMF之后很长的一段时间我一直在走弯路,最后发现是自己的测试数据并不方便手算而且一开始采用的模板本身有错误,另一方面因为我之前并没有接触过图论算法,对这些现学的算法实现和运行细节不熟悉。在调整心态之后我决定使用自己设计的图作为调试用例并慢节奏地调试理解,稳扎稳打。

这里有一个博客,作者的思路与我一致,其内容对我有很大帮助。

 

2.1 多服务器(固定)-多消费结点、无输出的版本

这是调试的一个版本,作为算法发展的基础。

技术分享
  1 #include<iostream>
  2 #include<string.h>
  3 #include<vector>
  4 #include<queue>
  5 #include<algorithm>
  6 using namespace std;
  7 
  8 const int maxm=10000+100;    //最大点数
  9 const int INF=0x3f3f3f3f;
 10 
 11 struct edge{        //边:起点、终点、容量、流量、单位费用
 12     int from,to,c,f,cost;
 13     edge(int a,int b,int m,int n,int p):from(a),to(b),c(m),f(n),cost(p){}
 14 };
 15 
 16 int aabs(int a){
 17     return a>=0?a:-a;
 18 }
 19 
 20 struct MCMF{
 21     int m,s,t;
 22     vector<edge> e;
 23     vector<int> g[maxm];
 24     int dis[maxm],a[maxm],p[maxm];
 25     bool vis[maxm];
 26 
 27     void init(int n){        //初始化函数
 28         for(int i=0;i<=n;i++)g[i].clear();
 29         e.clear();
 30     }
 31 
 32     void add(int a,int b,int c,int v){    //加边函数
 33         e.push_back(edge(a,b,c,0,v));
 34         e.push_back(edge(b,a,0,0,-v));
 35         m=e.size();
 36         g[a].push_back(m-2);
 37         g[b].push_back(m-1);
 38     }
 39 
 40     bool spfa(int& flow,int& cost){
 41         memset(dis,0x3f,sizeof(dis));
 42         memset(vis,0,sizeof(vis));
 43         queue<int>q;
 44         q.push(s);
 45         vis[s]=1;
 46         dis[s]=0;
 47         p[s]=0;
 48         a[s]=INF;
 49         while(!q.empty()){
 50             int u=q.front();q.pop();
 51             vis[u]=0;
 52             for(int i=0;i<g[u].size();i++){
 53                 edge tmp=e[g[u][i]];
 54                 if(dis[tmp.to]>dis[u]+tmp.cost &&tmp.c>tmp.f){
 55                     dis[tmp.to]=dis[u]+tmp.cost;
 56                     p[tmp.to]=g[u][i];
 57                     a[tmp.to]=min(a[u],tmp.c-tmp.f);
 58                     if(!vis[tmp.to]){
 59                         q.push(tmp.to);
 60                         vis[tmp.to]=1;
 61                     }
 62                 }
 63             }
 64         }
 65         if(dis[t]==INF)return 0;
 66         flow+=a[t];
 67         cost+=dis[t]*a[t];
 68         int u=t;
 69         while(u!=s){
 70             e[p[u]].f+=a[t];
 71             e[p[u]^1].f-=a[t];
 72             u=e[p[u]].from;
 73         }
 74         return 1;
 75     }
 76 
 77     void MF(int s,int t,int &flow,int &cost){    //调用的计算最小费用函数
 78         this->s=s;
 79         this->t=t;
 80         //int flow=0,cost=0;
 81         while(spfa(flow,cost));
 82         //return cost;
 83     }
 84 
 85 };
 86 
 87 int main()
 88 {
 89     freopen("C:\\\\Users\\\\lenovo\\\\Desktop\\\\工作\\\\华为挑战赛\\\\testCase0\\\\testCase4.txt", "r", stdin);
 90     
 91     //数据准备 
 92     int n, m, s, t, h;
 93     int from, to, cap, value;
 94     int flow, cost, need;
 95     int loc[maxm], k;
 96     MCMF mcmf;
 97     
 98     //输入第一行 
 99     cin>>n>>m>>h;
100     //初始化 
101     mcmf.init(n+h+2);
102     //输入网络节点并且add 
103     for( int i=1; i<=m; i++ )
104     {
105         cin>>from>>to>>cap>>value;
106         mcmf.add(from, to, cap, value);
107         mcmf.add(to, from, cap, value);
108     }
109     //输入消费结点、add零费用边、建立超级汇点 
110     for( int i=1; i<=h; i++ )
111     {
112         cin>>to>>from>>cap;
113         mcmf.add(from, to+n, cap, 0);
114         mcmf.add(to+n, from, cap, 0); 
115         
116         mcmf.add(to+n, n+h+1, cap, 0);    //汇点编号为 n+h+1 
117         mcmf.add(n+h+1, to+n, cap, 0);
118     }
119     //建立超级源点(以0结点为服务器)
120     k=2;
121     memset(loc,-1,sizeof(loc));
122     loc[0]=0;    loc[1]=1;
123     for(int i=0;i<k;i++)
124     {
125         mcmf.add(n+h+2, loc[i], cap, 0);    //源点编号为 n+h+2
126         mcmf.add(loc[i], n+h+2, cap, 0);
127     }
128     
129     mcmf.MF(n+h+1,n+h+2,flow,cost);
130     cout<<"flow= "<<flow<<endl<<"cost= "<<cost<<endl;
131     
132     fclose(stdin);
133 }
134 //多(固定)服务器单消费节点,含有超级结点 
View Code
技术分享
10 14 2

0 1 1 2
0 9 2 3
1 2 3 1
1 4 4 2
4 9 5 3
9 8 6 1
4 2 7 2
2 6 8 3
4 5 9 1
5 6 10 3
8 6 11 1
6 7 12 2
6 3 13 3
7 3 14 2

0 2 100
1 9 100
View Data

技术分享

 

2.2 引进DSF函数

以上是关于关于网络流算法的主要内容,如果未能解决你的问题,请参考以下文章

关于网络流算法

网络流初步

网络流:最大流之Dinic算法

网络流:最大流之SAP算法

网络流的$mathfrak{Dinic}$算法

网络流的C++代码实现与过程讲解