【最大流 模板題 EdmondsKarp】HDU
阿新 • • 發佈:2018-12-24
Problem Description
給你m,n分別代表m條邊,n個點。接下來給你m條邊,每條邊u,v,w。u->v流量的容量為w。有重邊
思路:模板題,所以給幾個模板 時間複雜度O(F*|E|),F 為最大流量,E 為邊的個數
EdmondsKarp-dfs-vector實現
//dfs實現
#include<bits/stdc++.h>
using namespace std;
const int N = 1000;
const int inf = 0x3f3f3f3f;
struct node
{
int to, cap, rev;//終點,容量,終點到起點的下標( a[temp.to][temp.rev].cap就代表反向邊 )
};
vector<node> a[N];//用vector存圖
int vis[N];
void add(int u, int v, int w)//存邊
{
a[u].push_back((node){v, w, a[v].size()});
a[v].push_back((node){u, 0, a[u].size() - 1});
}
int dfs(int s, int t, int f)
{
if(s == t) return f;//到達了終點返回
vis[s] = 1;//標記
for(int i = 0; i < a[s].size(); i++)
{
node &temp = a[s][i];//因為要改變圖的邊,所以取地址
if(!vis[temp.to] && temp.cap > 0)//沒有走過的點,並且容量不為0
{
int d = dfs(temp.to, t, min(f, temp.cap));//d為限制流量。核心min(f, temp.cap);
if(d > 0)//回溯的過程中,如果d>0,代表找到了增廣路
{
temp.cap -= d;//正向邊 -d
a[temp.to][temp.rev].cap += d;//反向邊 +d
return d;//繼續回溯
}
}
}
return 0;
}
int max_flow(int s, int t)
{
int flow = 0;//最大流
for(;;){
memset(vis, 0, sizeof(vis));
int d = dfs(s, t, inf);//搜增廣路,得到這條增廣路上限制容量
if(d == 0) return flow;//如果為0代表搜不到,直接返回輸出
flow += d;//搜到了,就疊加到最大流
}
}
int main()
{
int n, m, u, v, w;
while(~scanf("%d %d", &m, &n))
{
memset(a, 0, sizeof(a));//初始化
while(m--)
{
scanf("%d %d %d", &u, &v, &w);
add(u, v, w);
}
printf("%d\n", max_flow(1, n));
}
return 0;
}
EdmondsKarp-dfs-前向星實現
#include<bits/stdc++.h>
using namespace std;
#define mm 250
struct node
{
int to, w, next;
};
node Map[2 * mm];
int vis[mm], head[mm];
void add(int u, int v, int w, int &cnt)
{
Map[cnt].to = v;
Map[cnt].w = w;
Map[cnt].next = head[u];
head[u] = cnt++;
Map[cnt].to = u;
Map[cnt].w = 0;
Map[cnt].next = head[v];
head[v] = cnt++;
}
int dfs(int s, int t, int f)
{
vis[s] = 1;
if(s == t) return f;
for(int i = head[s]; ~i; i = Map[i].next)
{
int to = Map[i].to, &w = Map[i].w;
if(!vis[to] && w > 0)
{
int d = dfs(to, t, min(f, w));
if(d > 0)
{
w -= d;
Map[i^1].w += d;//反向邊表達
//下標0是正向1就是反向。1^1=0,0^1=1;其他都和vector一致
return d;
}
}
}
return 0;
}
int EK(int s, int t)//求最大流
{
int Max_flow = 0, d;
for(;;)
{
memset(vis, 0, sizeof(vis));
d = dfs(s, t, 0x3f3f3f3f);
if(d == 0) return Max_flow;//找不到增廣路
Max_flow += d;
}
}
int main()
{
int n, m, u, v, w;
while(~scanf("%d %d", &m, &n))
{
int cnt = 0;
memset(head, -1, sizeof(head));
while(m--)
{
scanf("%d %d %d", &u, &v, &w);//前向星
add(u, v, w, cnt);
}
printf("%d\n", EK(1, n));
}
return 0;
}
EdmondsKarp-bfs實現
//BFS實現
#include<bits/stdc++.h>
using namespace std;
const int N = 205;
const int inf = 0x3f3f3f3f;
int Map[N][N], Pre[N], Min_flow[N];//鄰接矩陣存邊,記錄路徑,記錄限制流量
int bfs(int s, int t)
{
memset(Pre, -1, sizeof(Pre));//初始化
queue<int> q;
Min_flow[s] = inf;//一開始限制流量是無窮
Pre[s] = 0;
q.push(s);
while(!q.empty())
{
s = q.front(); q.pop();
if(s == t) break;//到達終點、找到一條增廣路;
for(int i = 1; i <= t; i++)
{
if(Pre[i] == -1 && Map[s][i] > 0)//沒走過的點,容量大於0的點
{
//求限制流量
Min_flow[i] = min(Min_flow[s], Map[s][i]);
Pre[i] = s;//記錄路徑
q.push(i);//入佇列
}
}
}
if(Pre[t] == -1) return -1;//代表沒有找到增廣路
else return Min_flow[t];//找到了返回限制流量
}
int Ek(int s, int t)
{
int Max_flow = 0, flow;//最大流,限制流量
while((flow = bfs(s, t)) != -1)//如果為-1代表搜不到增廣路
{
Max_flow += flow;//更新最大流
int u = t;
while(u != 0)//增廣路 路徑上的邊,正向-flow,反向+flow
{
Map[Pre[u]][u] -= flow;
Map[u][Pre[u]] += flow;
u = Pre[u];
}
}
return Max_flow;
}
int main()
{
int m, u, v, w, n;
while(~scanf("%d %d", &m, &n))
{
memset(Map, 0, sizeof(Map));
while(m--)
{
scanf("%d %d %d", &u, &v, &w);
Map[u][v] += w; //有重邊
}
printf("%d\n", Ek(1, n));
}
return 0;
}