USACO Drainage Ditches解题报告

这道题是典型的max flow问题,也是我第一次实现max flow。感觉比想得要简单很多。参考了topcoder的tutorial: http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=maxFlow。用的是BFS发现从源到目的的“最短”路径(跳数短)。实现完成后参考标准答案,发现很多需要改进的地方。首先,这里两点之间可以有多条路径,我的处理方法是再加一个新的点。比如从a到b之间已经有一条路径了,我就再加上一个新的点c,把新的capacity赋给从a到c的路径,然后加一条从c到b的capacity无限大的路径。参考答案的方法是把两点之间的所有路径汇合起来,capacity为所有capacity之和,简单很多。另外,我用的是BFS,参考答案用的是改动的dijkstra,相当于给不同的点一个权值,应该类似于topcoder中给出的PFS方法。参考答案的方法应该快些。

代码如下:

/* 
ID: thestor1 
LANG: C++ 
TASK: ditch 
*/
#include <iostream>  
#include <cmath>  
#include <cstdio>  
#include <cstring>  
#include <climits>  
#include <cassert>  
#include <string>  
#include <vector>  
#include <set>
#include <map>  
#include <queue>  
#include <stack>  
#include <algorithm>

using namespace std;

int find_path(vector<vector<int> > &capacity, vector<vector<int> > adjs, const int sink)
{
	int M = capacity.size();
	std::vector<bool> visited(M, false);
	// from[x] is the previous vertex visited in the shortest path from the source to x
	std::vector<int> from(M, -1);
	queue<int> Q;
	Q.push(0);
	visited[0] = true;
	int where = -1, next = -1, prev = -1;
	bool found = false;
	while (!Q.empty())
	{
		where = Q.front();
		Q.pop();
		for (int i = 0; i < adjs[where].size(); ++i)
		{
			next = adjs[where][i];
			if (!visited[next] && capacity[where][next] > 0)
			{
				Q.push(next);
				visited[next] = true;
				from[next] = where;
				if (next == sink)
				{
					found = true;
					break;
				}
			}
		}
		if (found)
		{
			break;
		}
	}

	// we compute the path capacity
	where = sink;
	int path_cap = -1;
	while (from[where] > -1)
	{
		prev = from[where];
		if (path_cap > -1)
		{
			path_cap = min(path_cap, capacity[prev][where]);
		}
		else
		{
			path_cap = capacity[prev][where];
		}
		where = prev;
	}

	// we update the residual network; if no path is found the while loop will not be entered
	where = sink;
	while (from[where] > -1)
	{
		prev = from[where];
		capacity[prev][where] -= path_cap;
		capacity[where][prev] += path_cap;
		where = prev;
	}

	// if no path is found, path_cap is infinity
	if (path_cap == -1)
	{
		return 0;
	}
	return path_cap;
}


int main()
{
	FILE *fin  = fopen("ditch.in", "r");
	FILE *fout = fopen("ditch.out", "w");
	
	int N, M;
	fscanf(fin, "%d", &N);
	fscanf(fin, "%d", &M);
	vector<vector<int> > capacity(N + M, vector<int>(N + M, 0));
	vector<vector<int> > adjs(N + M, vector<int>());
	int additional = M;
	for (int i = 0; i < N; ++i)
	{
		int s, e, c;
		fscanf(fin, "%d", &s);
		fscanf(fin, "%d", &e);
		fscanf(fin, "%d", &c);
		if (capacity[s - 1][e - 1] != 0)
		{
			// cout<<"[debug]s:"<<s<<", e:"<<e<<endl;
			capacity[s - 1][additional] = c;
			adjs[s - 1].push_back(additional);
			adjs[additional].push_back(s - 1);

			// cout<<"[debug]INT_MAX:"<<INT_MAX<<endl;
			capacity[additional][e - 1] = INT_MAX;
			// capacity[e - 1][additional] = INT_MAX;
			adjs[additional].push_back(e - 1);
			adjs[e - 1].push_back(additional);

			additional++;
		}
		else
		{
			capacity[s - 1][e - 1] = c;
			adjs[s - 1].push_back(e - 1);
			adjs[e - 1].push_back(s - 1);
		}
	}
	
	// fprintf(fout, "d", mincycle);
	// for (int i = 0; i < N + M; ++i)
	// {
	// 	cout<<i + 1<<":"<<endl;
	// 	for (int j = 0; j < N + M; ++j)
	// 	{
	// 		if (capacity[i][j])
	// 		{
	// 			cout<<j + 1<<":"<<capacity[i][j]<<endl;
	// 		}
	// 	}
	// }

	// max flow
	int maxflow = 0;

	while (true)
	{
		int path_cap = find_path(capacity, adjs, M - 1);
		if (path_cap == 0)
		{
			break;
		}
		else
		{
			maxflow += path_cap;
		}
	}

	// cout<<"[debug]maxflow: "<<maxflow<<endl;
	fprintf(fout, "%d\n", maxflow);

	fclose(fin);
	fclose(fout);
	return 0;  
}


你可能感兴趣的:(USACO Drainage Ditches解题报告)