hdu3549 flow problem

第一次做網絡流, 紀念一小下吧

代碼寫得比較蹉, 很多能優化的地方都只能放棄, 只是體驗一下這個過程, 優化了反而複雜了

EK算法

鄰接矩陣表示:

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <queue>
#pragma warning(disable:4996)
using namespace std;

#define CLR(arr, v) memset(arr, v, sizeof(arr))
const int M = 20;

int map[M][M];
int f[M][M];
int vexNum, edgeNum;
int s, t;

int path[20], flow[20];

bool vis[20];

bool bfs()
{
	queue<int> Q;
	
	CLR(flow, 0);
	CLR(vis, false);
	vis[s] = true;
	Q.push(s);
	flow[s] = 1e9;
	while(!Q.empty())
	{
		int top = Q.front();

		for(int i = 1; i <= vexNum; i++)
		{
			if(top != i && !vis[i] && map[top][i] > f[top][i])
			{
				path[i] = top;
				vis[i] = true;
				flow[i] = min(flow[top], map[top][i] - f[top][i]);    //注意是flow[top]
				if(i == t)
					return true;
				Q.push(i);
			}
		}
		Q.pop();
	}
	return false;
}

int ek()
{
	int maxFlow = 0, j;
	CLR(f, 0);
	while(bfs())
	{
		for(int j = t, i = path[j]; j != s;)
		{
			f[i][j] += flow[t];
			f[j][i] -= flow[t];      //更新反向邊
			j = i;
			i = path[i];
		}
		maxFlow += flow[t];
	}
	return maxFlow;
}

int main()
{
	int ncase, tmp = 1, u, v, w;
	scanf("%d", &ncase);
	while(ncase--)
	{
		CLR(map, 0);
		scanf("%d %d", &vexNum, &edgeNum);
		for(int i = 0; i < edgeNum; i++)
		{
			scanf("%d %d %d", &u, &v, &w);
			map[u][v] += w;
		}
		s = 1, t = vexNum;
		int ans = ek();
		printf("Case %d: %d\n", tmp++, ans);
	}
	return 0;
}



鄰接表實現:


#include <queue>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

#define CLR(a, val) memset(a, val, sizeof(a))
#pragma warning(disable:4996)

using namespace std;

const int MaxV = 100;
const int MaxE = 2005;     //必須注意這裏的2倍
const int INF = 1e9;

template<int MaxV, int MaxE>
struct Graph
{
	struct Vertes
	{
		int head;
	}V[MaxV];
	struct Edge
	{
		int arc, c, f, next;
		Edge(int arc, int c, int f, int next):arc(arc), c(c), f(f), next(next){}
		Edge(){}
	}E[MaxE];
	int top;
	void init()
	{
		top = 0;
		CLR(V, -1);
	}
	void addEdge(int u, int v, int w)
	{
		E[top] = Edge(v, w, 0, V[u].head);
		V[u].head = top++;
		E[top] = Edge(u, 0, 0, V[v].head);
		V[v].head = top++;
	}
};



int vexNum, edgeNum;
int s, t;

Graph<MaxV, MaxE> g;

int path[MaxE];
int flow[MaxE];
bool bfs(int s, int t)
{
	CLR(flow, 0);
	queue<int> Q;
	Q.push(s);
	flow[s] = INF;
	while(!Q.empty())
	{
		int u = Q.front();
		for(int i = g.V[u].head; i != -1; i = g.E[i].next)
		{
			int v = g.E[i].arc;
			if(!flow[v] && g.E[i].c - g.E[i].f > 0)
			{
				path[v] = i;
				flow[v] = min(flow[u], g.E[i].c - g.E[i].f);
				if(v == t)
					return true;
				Q.push(v);
			}
		}
		Q.pop();
	}
	return false;
}

int ek(int s, int t)
{
	int i, maxFlow = 0;
	while(bfs(s, t))
	{
		for(int v = t; v != s; v = g.E[i ^ 1].arc)
		{
			i = path[v];
			g.E[i].f += flow[t];
			g.E[i ^ 1].f -= flow[t];	
		}
		maxFlow += flow[t];
	}
	return maxFlow;
}
void debug()
{
	for(int i = 1; i <= vexNum; i++)
	{
		cout << i << ":";
		for(int j = g.V[i].head; j != -1; j = g.E[j].next)
		{
			cout << g.E[j].arc << " ";
		}
		cout << endl;
	}
}
int main()
{
	//freopen("data_in.txt", "r", stdin);
	int ncase, tmp = 1;
	scanf("%d", &ncase);
	while(ncase--){
		g.init();
		int u, v, w;
		scanf("%d %d", &vexNum, &edgeNum);
		for(int i = 0; i < edgeNum; i++)
		{
			scanf("%d %d %d", &u, &v, &w);
			g.addEdge(u, v, w);
		}
		//cin >> s >> t;
		//debug();
		
		//cout << "Case " << tmp++ << ": " << ek(1, vexNum) << endl;
		printf("Case %d: %d\n", tmp++, ek(1, vexNum));
	}
	return 0;
}

Dinic 算法


#include <queue>
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>

#define CLR(a, val) memset(a, val, sizeof(a))
#pragma warning(disable:4996)

using namespace std;

const int MaxV = 100;
const int MaxE = 2005 << 1;
const int INF = 1e9;

template<int MaxV, int MaxE>
struct Graph
{
	struct Vertes
	{
		int head;
	}V[MaxV];
	struct Edge
	{
		int arc, c, f, next;
		Edge(int arc, int c, int f, int next):arc(arc), c(c), f(f), next(next){}
		Edge(){}
	}E[MaxE];
	int top;
	void init()
	{
		top = 0;
		CLR(V, -1);
	}
	void addEdge(int u, int v, int w)
	{
		E[top] = Edge(v, w, 0, V[u].head);
		V[u].head = top++;
		E[top] = Edge(u, 0, 0, V[v].head);
		V[v].head = top++;
	}
};



int vexNum, edgeNum;
int s, t;

Graph<MaxV, MaxE> g;


int level[MaxV];
int path[MaxV];

bool bfs()
{
	queue<int> Q;
	CLR(level, -1);
	level[s] = 0;
	Q.push(s);
	while(!Q.empty())
	{
		int u =  Q.front();

		for(int i = g.V[u].head; i != -1; i = g.E[i].next)
		{
			int j = g.E[i].arc;
			if(level[j] == -1 && g.E[i].c)
			{
				level[j] = level[u] + 1;
				Q.push(j);
			}
		}
		Q.pop();
	}
	return level[t] != -1;
}

int dfs(int v, int c)
{
	if(v == t)
		return c;
	int sum = c;

	for(int i = g.V[v].head; i != -1; i = g.E[i].next)
	{
		int j = g.E[i].arc;

		if(g.E[i].c > 0 && level[j] == level[v] + 1)
		{
			int a = dfs(j, min(c, g.E[i].c));
			g.E[i].c -= a;
			g.E[i ^ 1].c += a;
			c -= a;
		}
	}
	return sum - c;
}



int dinic()
{
	int ans =0;
	while(bfs())
	{
		ans += dfs(s, INF);
	}
	return ans;
}
int main()
{
	//freopen("data_in.txt", "r", stdin);
	int ncase, tmp = 1;
	scanf("%d", &ncase);
	while(ncase--){
		g.init();
		int u, v, w;
		scanf("%d %d", &vexNum, &edgeNum);
		for(int i = 0; i < edgeNum; i++)
		{
			scanf("%d %d %d", &u, &v, &w);
			g.addEdge(u, v, w);
		}
		s = 1, t = vexNum;
		printf("Case %d: %d\n", tmp++, dinic());
	}
	return 0;
}
dinic 參考代碼:http://blog.csdn.net/birdforever/article/details/5874780



SAP 算法

鄰接矩陣實現:

/*
測試用例: 
6 5
1 2 2
1 3 5
2 4 1
3 4 6
3 5 1
4 5 5
*/
#include<stdio.h>
#include<string.h>
#include <iostream>
#include <iomanip>
using namespace std;
#pragma warning(disable:4996)
#define CLR(arr, v) memset(arr, v, sizeof(arr))
#define print(a) cout << #a << ": " << a << endl;
#define INF 1<<29;

const int M = 100;

struct sap
{
	const int m;
	const int s, t;
	
	int cf[M][M];
	int flow;
	int h[M];
	int vh[M];
	int cf_path;
	bool flag;

	sap(int m, int s, int t):m(m), s(s), t(t)
	{
		CLR(cf, 0);
		CLR(h, 0);
		CLR(vh, 0);
		flow = 0;
		flag = false;
	}


	void find_path(int cur)
	{
		if(t == cur)
		{
			flow += cf_path;
			flag = true;
			return;
		}

		int tmp_cf_path = cf_path;
		int minH = m - 1;
		int i;
		for(i = 1; i <= m; i++)
		{
			if(cf[cur][i])
			{
				if(h[i] == h[cur] - 1)
				{
					cf_path = min(cf_path, cf[cur][i]);
					
					find_path(i);

					if(h[1] >= m)
						return;
					if(flag)
						break;
					if(!flag)
						cf_path = tmp_cf_path;
				}
				minH = min(minH, h[i]);
			}
		}
		if(flag)
		{
			cf[cur][i] -= cf_path;
			cf[i][cur] += cf_path;
		}
		else
		{
			vh[h[cur]]--;
			if(vh[h[cur]] == 0)
				h[1] = m;

			h[cur] = minH + 1;
			vh[h[cur]] += 1;
		}
	}

	int solve()
	{
		vh[0] = m;
		flow = 0;
		while(h[1] < m)
		{
			flag = false;
			cf_path = INF;
			find_path(s);			
		}
		return flow;
	}
    void addEdge(int x,int y,int c){
            cf[x][y]+=c;
    }
};

int main()
{
    int n;	//有向邊數
	int m;	//頂點數
	int ncase, tmp = 1;
	scanf("%d", &ncase);
    while(ncase--)
    {
		scanf("%d %d", &m, &n);
        sap nt= sap(m, 1, m);
        for(int i=1;i<=n;i++)
        {
            int x,y,c;
            scanf("%d %d %d",&x,&y,&c);
            nt.addEdge(x,y,c);
        }
		printf("Case %d: %d\n",tmp++, nt.solve());
    }
    return 0;
} 


sap鄰接矩陣參考代碼:http://chuanwang66.iteye.com/blog/1450715


鄰接表實現:

//SPA
#include <cstring>
#include <cstdio>
#include <queue>
#include <algorithm>

#define CLR(arr, val) memset(arr, val, sizeof(arr))
#pragma warning(disable:4996)

using namespace std;

const int MaxV = 20;
const int MaxE = 1000 << 1;
const int INF = 1e9;

struct Graph
{
	struct Vertex
	{
		int head;
	}V[MaxV];

	struct Edge 
	{
		int v, c, f, next;
		Edge(){}
		Edge(int v,int c, int f, int next):v(v), c(c), f(f), next(next){}
	}E[MaxE];

	void init()
	{
		top = 0;
		CLR(V, -1);
	}
	void addEdge(int u, int v,int w)
	{
		E[top] = Edge(v, w, 0, V[u].head);
		V[u].head = top++;
		E[top] = Edge(u, 0, 0, V[v].head);
		V[v].head = top++;
	}
	int top;
};

int h[MaxV];        //高度
int path[MaxV];     //迴路
int gap[MaxV];      //gap優化
int cur[MaxV];      //當前弧優化
int s, t;
int vexNum, edgeNum;
Graph g;

void setHeight()
{
	CLR(gap, 0);
	CLR(h, -1);
	h[t] = 0;

	queue<int>Q;
	Q.push(t);
	while(!Q.empty())
	{
		int top = Q.front();
		gap[ h[top] ]++;
		for(int i = g.V[top].head; i != -1; i = g.E[i].next)
		{
			int v = g.E[i].v;
			if(h[v] == -1)
			{
				h[v] = h[top] + 1;
				Q.push(v);
			}
		}
		Q.pop();
	}
}

int sap()
{
	setHeight();
	int maxFlow = 0, u = s;
	int flow = INF;
	for(int i = 0; i <= vexNum; i++)
		cur[i] = g.V[i].head;
	while(h[s] < vexNum)
	{
		int &i = cur[u];
		for(; i != -1; i = g.E[i].next)
		{
			int v = g.E[i].v;
			if(g.E[i].c > g.E[i].f && h[u] == h[v] + 1)
			{
				u = v;
				path[v] = i;
				flow = min(flow, g.E[i].c - g.E[i].f);
				if(u == t)
				{
					while(u != s)
					{
						int j = path[u];
						g.E[j].f += flow;
						g.E[j ^ 1].f -= flow;
						u = g.E[j ^ 1].v;
					}
					maxFlow += flow;
					flow = INF;
				}
				break;
			}
		}

		if(i == -1)
		{
			if(--gap[ h[u] ] == 0)
				break;
			int minH = vexNum - 1;
			cur[u] = g.V[u].head;
			for(int j = g.V[u].head; j != -1; j = g.E[j].next)
				if(g.E[j].c > g.E[j].f)
					minH = min(minH, h[g.E[j].v]);
			h[u] = minH + 1;
			++gap[ h[u] ];
			if(u != s)
				u = g.E[path[u] ^ 1].v;
		}
	}
	return maxFlow;	
}


int main()
{
	int ncase, tmp = 1;
	scanf("%d", &ncase);
	while(ncase--)
	{
		g.init();
		scanf("%d %d", &vexNum, &edgeNum);
		while(edgeNum--)
		{
			int u, v, w;
			scanf("%d %d %d", &u, &v, &w);
			g.addEdge(u, v, w);
		}
		s = 1, t = vexNum;
		printf("Case %d: %d\n", tmp++, sap());
	}
	return 0;
}

spa鄰接表參考:http://blog.csdn.net/dgq8211/article/details/7799229


用三個算法同時交了一次, 由於點有20個, 邊有1000條;

ek 算法是用鄰接矩陣實現是100多ms, 而用鄰接表是200多ms

用dinic算法只用了鄰接表, 是600+ ms

用SAP 的鄰接矩陣是  100+, 鄰接表也是100+;


看來SAP算法還是比較不錯的 



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章