UvaLive 2197 Paint the Roads(费用流)

题目地址:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=198

思路:

1.要求每点在k个边不相交环中,则每个点入度与出度相等,且每个点度均为k。

2.拆点。将每点拆为i和i',对于原图中的边i->j,连边i->j',容量为1,费用为边的长度。从源点S到每一点i连边,容量为k,费用为0;从每一点i'向汇点连边,容量为k,费用为0.

3.求最小费用流即为最小花费。

4.若S到i的流量不为k或i'到T的流量不为k,则无解。

#include
#include
#include
#include
#include
#include
#define debug
using namespace std;

const int maxn = 100 + 50;
const int INF = 0x3f3f3f3f;

int S, T;

struct Edge
{
	int from, to, cap, flow, cost;
	Edge(int u,int v,int c,int f,int w):from(u),to(v),cap(c),flow(f),cost(w){}
};

struct MM
{
	vector edges;
	vector G[maxn];
	vector flag;
	int n, m, s, t, cost;
	int p[maxn], a[maxn];
	int inq[maxn], d[maxn];

	void init(int n)
	{
		this->n = n;
		flag.clear();
		for (int i = 0; i <= n; i++) G[i].clear();
		edges.clear();
	}

	void addEdge(int from, int to, int cap, int cost)
	{
		edges.push_back(Edge(from, to, cap, 0, cost));
		edges.push_back(Edge(to, from, 0, 0, -cost));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
		if (from == S || to == T) flag.push_back(m - 2);
	}

	bool BF(int s, int t, int& flow, int& cost)
	{
		for (int i = 0; i <= n; i++) d[i] = INF;
		memset(inq, 0, sizeof(inq));
		d[s] = 0, inq[s] = 1, p[s] = 0;
		queue q;
		q.push(s), a[s] = INF;
		
		while (!q.empty())
		{
			int u = q.front();
			q.pop(), inq[u] = 0;
			for (int i = 0; i < G[u].size(); i++)
			{
				Edge& e = edges[G[u][i]];
				if (e.cap > e.flow&&d[e.to] > d[u] + e.cost)
				{
					d[e.to] = d[u] + e.cost;
					p[e.to] = G[u][i];
					a[e.to] = min(a[u], e.cap - e.flow);
					if (!inq[e.to])
					{
						q.push(e.to);
						inq[e.to] = 1;
					}
				}
			}
		}
		
		if (d[t] == INF) return false;
		flow += a[t];
		cost += d[t] * a[t];
		for (int u = t; u != s; u = edges[p[u]].from)
		{
			edges[p[u]].flow += a[t];
			edges[p[u] ^ 1].flow -= a[t];
		}
		return true;
	}

	int mcmf(int s, int t, int& cost)
	{
		this->s = s, this->t = t;
		int flow = 0;
		cost = 0;
		while (BF(s, t, flow, cost));
		return flow;
	}
};

MM g;
int n, m, k;

int check()
{
	for (int i = 0; i < g.flag.size(); i++)
	{
		Edge& e = g.edges[g.flag[i]];
		if (e.flow != k) return 0;
	}
	return 1;
}

int main()
{
#ifdef debu
	freopen("in.txt", "r", stdin);
#endif

	int t;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d%d", &n, &m, &k);
		g.init(2 * n + 1);
		S = 0, T = 2 * n + 1;
		for (int i = 0; i < m; i++)
		{
			int u, v, d;
			scanf("%d%d%d", &u, &v, &d);
			u++, v++;
			g.addEdge(u, v + n, 1, d);
		}

		for (int i = 1; i <= n; i++)
		{
			g.addEdge(S, i, k, 0);
			g.addEdge(i + n, T, k, 0);
		}

		int cost = 0;
		int flow = g.mcmf(S, T, cost);
		
		if (!check()) printf("-1\n");
		else printf("%d\n", cost);
	}
	return 0;
}




你可能感兴趣的:(OJ_UVA,网络流_最小费用流,ACM)