文献阅读01-1-空间众包-最大化任务分配数量-代码实现

代码介绍:

       文件数据格式:点的数量,边的数量,源点序号,汇点序号

                每条边:起点,终点,容量

从文件中读取数据,构建网络流图,使用dinic算法求解最大流,采用数组邻接表存储数据。

 

求最大流过程:不断找一条源点到汇点的路径,若有,找出增广路径上每一段权值的最小值,然后构建残余网络。再在残余网络上寻找新的路径,再依据路径的最小值,构建新的残余网络,再寻找新的路径...直至某个残余网络找不到从源点到汇点的路径为止,最大流即为每次最小值之和。

 

Dinic算法:

       先使用宽度优先搜索,根据源点到每个点的最短距离(边数)不同,对每个点进行分层,只要进行到计算出汇点的层次数,即为分层成功。

       之后利用深度优先搜索从前一层向后一层反复寻找增广路径,寻找的增广路径要求满足所有的点分别属于不同的层,且点应满足deppv=deppv-1+1。DFS过程中,进行到了汇点,则说明找到了一条增广路径,此时对总流量进行增加,并消减增广路径各边的容量,并添加反向边,即进行增广。找到一条增广路径后,回溯继续寻找下一个增广路径。

       DFS结束后,对残余网络再次进行分层,当分层操作无法算出汇点的层次是,即求得最大流。

   头文件:

  1 #include <queue>
  2 #include <fstream>
  3 #include <iostream>
  4 #include <string>
  5 using namespace std;
  6 const int inf = 0x3f3f3f3f;
  7 const int worker_number = 5000;
  8 const int task_number = 5000;
  9 
 10 struct Edge
 11 {
 12     int to;
 13     int next;
 14     int cap;
 15 };
 16 
 17 class Graph
 18 {
 19 private:
 20     int src;//源点
 21     int dst;//汇点
 22     int edge_num;//边数
 23     int note_num;//点数
 24     int num;
 25     int max_flow;
 26     int head[worker_number + task_number + 3];
 27     int cur[worker_number + task_number + 3];
 28     int level[worker_number + task_number];
 29     Edge edges[worker_number + task_number];
 30     queue<int> Q;
 31     void add_edge(int from,int to,int dis);
 32     bool bfs(int begin, int end);
 33     int dfs(int now,int flow);
 34     
 35 
 36 public:
 37     Graph(int n = 0, int m = 0, int s = 0, int d = 0);
 38     void read(string file_name);//从文件中读取数据
 39     int Dinic();
 40 };
 41 
 42 Graph::Graph(int n,int m,int s,int d)
 43 {
 44     this->note_num = n;
 45     this->edge_num = m;
 46     this->src = s;
 47     this->dst = d;
 48     this->max_flow = 0;
 49     this->num = -1;
 50 
 51     memset(this->head, -1, sizeof(this->head));
 52     memset(this->cur, -1, sizeof(this->cur));
 53     memset(this->level, -1, sizeof(this->level));
 54 }
 55 
 56 void Graph::add_edge(int from,int to,int dis)
 57 {
 58     this->edges[++this->num].next = this->head[from];
 59     this->edges[this->num].to = to;
 60     this->edges[this->num].cap = dis;
 61     this->head[from] = this->num;    
 62 }
 63 
 64 void Graph::read(string file_name)
 65 {
 66     ifstream fin(file_name);
 67     int x, y, z;
 68 
 69     if (fin.good())
 70     {
 71         //n结点数,m边数,s源点,d汇点
 72         fin >> this->note_num >> this->edge_num >> this->src >> this->dst;
 73         this->num = -1;
 74 
 75         for (int i = 0;i < this->edge_num;i++)
 76         {
 77             //边:起点,终点,容量
 78             fin >> x >> y >> z;
 79 
 80             this->add_edge(x, y, z);//添加边
 81             this->add_edge(y, x, 0);//添加反向边
 82         }
 83     }
 84     else
 85     {
 86         cout << "文件打开失败!" << endl;
 87         exit(0);
 88     }
 89 
 90     fin.close();
 91 }
 92 
 93 //利用bfs进行分层
 94 bool Graph::bfs(int begin, int end)
 95 {
 96     memset(this->level, -1, sizeof(this->level));//更新层次,对残余网络进行分层
 97     int now;//当前点
 98 
 99     while (!this->Q.empty())this->Q.pop();
100     this->level[begin] = 0;//起点深度为0
101     this->Q.push(begin);
102 
103     while (!this->Q.empty())
104     {
105         now = this->Q.front();
106         this->Q.pop();
107 
108         for (int i = this->head[now];i != -1;i = this->edges[i].next)
109         {
110             //如果该点没有被标记层次并且该边的流量不为零
111             if (this->level[this->edges[i].to] == -1 && this->edges[i].cap)
112             {
113                 this->level[this->edges[i].to] = this->level[now] + 1;
114                 this->Q.push(this->edges[i].to);
115             }
116         }
117     }
118     
119     return this->level[this->dst] != -1;//若没有到达汇点,则返回false
120 }
121 
122 //flow为源点到now的路径中的最小边权
123 int Graph::dfs(int now, int flow)
124 {
125     if (now == this->dst)return flow;//如果当前点为汇点,则返回flow
126 
127     int detla = flow, d, f;
128     for (int i = this->cur[now];i != -1;i = this->edges[i].next)
129     {
130         //寻找路径时,点要属于不同的层次并且边为通
131         if (this->level[this->edges[i].to] == (this->level[now] + 1) && (this->edges[i].cap > 0))
132         {
133             //向下递归,求后续结点的最大流量,即最小边权
134             this->cur[now] = this->edges[i].next;
135             d = (detla < this->edges[i].cap) ? detla : this->edges[i].cap;
136             f = this->dfs(this->edges[i].to, d);
137 
138             this->edges[i].cap -= f;
139             //处理反向边,存边时从0开始,边和其反向边相邻
140             this->edges[i ^ 1].cap += f;
141             detla -= f;//更新本节点的残余量
142             //若本节点的残余量消耗完,则返回
143             if (detla == 0)break;
144         }
145     }
146 
147     return flow - detla;//返回该点已经被允许流过的流量
148 }
149 
150 int Graph::Dinic()
151 {
152     while (this->bfs(this->src, this->dst))
153     {
154         for (int i = 1;i <= this->note_num;i++)this->cur[i] = this->head[i];
155         this->max_flow += this->dfs(this->src, inf);
156     }
157 
158     return this->max_flow;
159 }

  源文件:

 1 #include "标头.h"
 2 
 3 int main()
 4 {
 5     Graph G;
 6     string file_name;
 7 
 8     cout << "请输入存储数据的文件" << endl;
 9     cin >> file_name;
10 
11     G.read(file_name);
12     cout << "最大流:" << G.Dinic() << endl;
13 
14     return 0;
15
posted @ 2020-02-21 12:05  方知有  阅读(312)  评论(0编辑  收藏  举报