文献阅读01-1-空间众包-最大化任务分配数量-代码实现
Posted fangzhiyou
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了文献阅读01-1-空间众包-最大化任务分配数量-代码实现相关的知识,希望对你有一定的参考价值。
代码介绍:
文件数据格式:点的数量,边的数量,源点序号,汇点序号
每条边:起点,终点,容量
从文件中读取数据,构建网络流图,使用dinic算法求解最大流,采用数组邻接表存储数据。
求最大流过程:不断找一条源点到汇点的路径,若有,找出增广路径上每一段权值的最小值,然后构建残余网络。再在残余网络上寻找新的路径,再依据路径的最小值,构建新的残余网络,再寻找新的路径...直至某个残余网络找不到从源点到汇点的路径为止,最大流即为每次最小值之和。
Dinic算法:
先使用宽度优先搜索,根据源点到每个点的最短距离(边数)不同,对每个点进行分层,只要进行到计算出汇点的层次数,即为分层成功。
之后利用深度优先搜索从前一层向后一层反复寻找增广路径,寻找的增广路径要求满足所有的点分别属于不同的层,且点应满足deppv=deppv-1+1。DFS过程中,进行到了汇点,则说明找到了一条增广路径,此时对总流量进行增加,并消减增广路径各边的容量,并添加反向边,即进行增广。找到一条增广路径后,回溯继续寻找下一个增广路径。
DFS结束后,对残余网络再次进行分层,当分层操作无法算出汇点的层次是,即求得最大流。
头文件:
#include <queue>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;
const int inf = 0x3f3f3f3f;
const int worker_number = 5000;
const int task_number = 5000;
struct Edge
{
int to;//所指向的点
int next;//下一条边
int cap;//该边容量
};
class Graph
{
private:
int src;//源点
int dst;//汇点
int edge_num;//边数
int note_num;//点数
int num;//边的编号
int max_flow;//最大流量
int head[worker_number + task_number + 3];//编号1~n单元格来存储1~n号顶点的第一条边的编号
int cur[worker_number + task_number + 3];//用来复制head数组的值
int level[worker_number + task_number];//每点的层次
Edge edges[worker_number + task_number];//存储边
queue<int> Q;
void add_edge(int from,int to,int dis);//对网络流图增加边
bool bfs(int begin, int end);//进行分层
int dfs(int now,int flow);//寻找增广路径
public:
Graph(int n = 0, int m = 0, int s = 0, int d = 0);//初始化,n点的数量,m边的数量,s源点编号,t汇点编号
void read(string file_name);//从文件中读取数据
int Dinic();
};
Graph::Graph(int n,int m,int s,int d)
{
this->note_num = n;
this->edge_num = m;
this->src = s;
this->dst = d;
this->max_flow = 0;
this->num = -1;
memset(this->head, -1, sizeof(this->head));
memset(this->cur, -1, sizeof(this->cur));
memset(this->level, -1, sizeof(this->level));
}
void Graph::add_edge(int from,int to,int dis)
{
this->edges[++this->num].next = this->head[from];
this->edges[this->num].to = to;
this->edges[this->num].cap = dis;
this->head[from] = this->num;
}
void Graph::read(string file_name)
{
ifstream fin(file_name);
int x, y, z;
if (fin.good())
{
//n结点数,m边数,s源点,d汇点
fin >> this->note_num >> this->edge_num >> this->src >> this->dst;
this->num = -1;
for (int i = 0;i < this->edge_num;i++)
{
//边:起点,终点,容量
fin >> x >> y >> z;
this->add_edge(x, y, z);//添加边
this->add_edge(y, x, 0);//添加反向边
}
}
else
{
cout << "文件打开失败!" << endl;
exit(0);
}
fin.close();
}
//利用bfs进行分层
bool Graph::bfs(int begin, int end)
{
memset(this->level, -1, sizeof(this->level));//更新层次,对残余网络进行分层
int now;//当前点
while (!this->Q.empty())this->Q.pop();
this->level[begin] = 0;//起点深度为0
this->Q.push(begin);
while (!this->Q.empty())
{
now = this->Q.front();
this->Q.pop();
for (int i = this->head[now];i != -1;i = this->edges[i].next)
{
//如果该点没有被标记层次并且该边的流量不为零
if (this->level[this->edges[i].to] == -1 && this->edges[i].cap)
{
this->level[this->edges[i].to] = this->level[now] + 1;
this->Q.push(this->edges[i].to);
}
}
}
return this->level[this->dst] != -1;//若没有到达汇点,则返回false
}
//flow为源点到now的路径中的最小边权
int Graph::dfs(int now, int flow)
{
if (now == this->dst)return flow;//如果当前点为汇点,则返回flow
int detla = flow, d, f;
for (int i = this->cur[now];i != -1;i = this->edges[i].next)
{
//寻找路径时,点要属于不同的层次并且边为通
if (this->level[this->edges[i].to] == (this->level[now] + 1) && (this->edges[i].cap > 0))
{
//向下递归,求后续结点的最大流量,即最小边权
this->cur[now] = this->edges[i].next;// 即先定义一个cur数组,在dfs之前把邻接表的head数组拷贝到cur里面,然后在遍历now的时候同时把cur里面的边的下标后移,以达到将用完的边略去的目的
d = (detla < this->edges[i].cap) ? detla : this->edges[i].cap;
f = this->dfs(this->edges[i].to, d);
this->edges[i].cap -= f;
//处理反向边,存边时从0开始,边和其反向边相邻
this->edges[i ^ 1].cap += f;
detla -= f;//更新本节点的残余量
//若本节点的残余量消耗完,则返回
if (detla == 0)break;
}
}
return flow - detla;//返回该点已经被允许流过的流量
}
int Graph::Dinic()
{
while (this->bfs(this->src, this->dst))
{
for (int i = 1;i <= this->note_num;i++)this->cur[i] = this->head[i];// 把邻接表的head数组拷贝到cur里面
this->max_flow += this->dfs(this->src, inf);
}
return this->max_flow;
}
源文件:
#include "标头.h"
int main()
{
Graph G;
string file_name;
cout << "请输入存储数据的文件" << endl;
cin >> file_name;
G.read(file_name);
cout << "最大流:" << G.Dinic() << endl;
return 0;
}
以上是关于文献阅读01-1-空间众包-最大化任务分配数量-代码实现的主要内容,如果未能解决你的问题,请参考以下文章