Uva 10983 Buy one, get the rest free(二分+最大流)

题目地址:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1924

思路:

1.二分所需花费cost,每次只选择不大于cost的航班。

2.设源点S,汇点T。对于每个城市,表示为二元组(i,t),代表第t天处于第i个城市。从S到每一(i,0)连边,容量为每个城市人数;从(n,d)到T连边,容量为INF。

3.对于每个个航班,从城市i到城市j,出发时间为e,到达时间为e+1。连边(i,e)->(j,e+1),容量为航班限制人数。

4.由于可在城市停留,连边(i,e)->(i,e+1),容量为INF。

5.若最大流等于总人数,则当前花费可满足条件。

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

const int maxn = 400 + 50;
const int maxm = 1000 + 50;
const int INF = 0x3f3f3f3f;

struct Edge
{
	int from, to, cap, flow;
	Edge(int a, int b, int c, int d) :from(a), to(b), cap(c), flow(d) {}
};

struct Dinic
{
	int n, m, s, t;
	vector edges;
	vector G[maxn];
	bool vis[maxn];
	int d[maxn];
	int cur[maxn];
	void init(int n)
	{
		this->n = n;
		for (int i = 0; i <= n; i++) G[i].clear();
		edges.clear();
	}
	void addEdge(int from, int to, int cap)
	{
		edges.push_back(Edge(from, to, cap, 0));
		edges.push_back(Edge(to, from, 0, 0));
		m = edges.size();
		G[from].push_back(m - 2);
		G[to].push_back(m - 1);
	}
	bool BFS()
	{
		memset(vis, 0, sizeof(vis));
		queue Q;
		Q.push(s);
		vis[s] = 1;
		d[s] = 0;
		while (!Q.empty())
		{
			int x = Q.front();
			Q.pop();
			for (int i = 0; i < G[x].size(); i++)
			{
				Edge& e = edges[G[x][i]];
				if (!vis[e.to] && e.cap > e.flow)
				{
					vis[e.to] = 1;
					d[e.to] = d[x] + 1;
					Q.push(e.to);
				}
			}
		}
		return vis[t];
	}
	int DFS(int x, int a)
	{
		if (x == t || a == 0) return a;
		int flow = 0, f;
		for (int& i = cur[x]; i < G[x].size(); i++)
		{
			Edge& e = edges[G[x][i]];
			if (d[x] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0)
			{
				e.flow += f;
				edges[G[x][i] ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (a == 0) break;
			}
		}
		return flow;
	}
	int MaxFlow(int s, int t)
	{
		this->s = s;
		this->t = t;
		int flow = 0;
		while (BFS())
		{
			memset(cur, 0, sizeof(cur));
			flow += DFS(s, INF);
		}
		return flow;
	}
};

struct Node
{
	int u, v, c, p, e;
};

Dinic g;
int p[40];
Node a[maxm];
int id[40][15];
int n, d, m, maxx;
int cnt, S, T, sum;

int check(int x)
{
	g.init(cnt + 1);
	for (int i = 1; i <= n; i++)
	{
		g.addEdge(S, id[i][0], p[i]);
		for (int j = 0; j <= d; j++)
		{
			g.addEdge(id[i][j], id[i][j + 1], INF);
		}
	}
	g.addEdge(id[n][d], T, INF);

	for (int i = 0; i < m; i++)
	{
		Node& tmp = a[i];
		if (tmp.p <= x)
		{
			g.addEdge(id[tmp.u][tmp.e], id[tmp.v][tmp.e + 1], tmp.c);
		}
	}
	
	return g.MaxFlow(S, T) == sum;
}

void init()
{
	cnt = 0;
	sum = 0;
	maxx = -INF;
	memset(id, 0, sizeof(id));
}

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

	int t, cas = 0;
	scanf("%d", &t);
	while (t--)
	{
		scanf("%d%d%d", &n, &d, &m);
		init();
		for (int i = 1; i <= n; i++)
		{
			for (int j = 0; j <= d; j++)
			{
				id[i][j] = ++cnt;
			}
		}

		for (int i = 0; i < m; i++)
		{
			int u, v, c, p, e;
			scanf("%d%d%d%d%d", &u, &v, &c, &p, &e);
			a[i] = Node{ u,v,c,p,e };
			maxx = max(maxx, p);
		}

		S = 0, T = cnt + 1;

		g.init(cnt + 1);

		for (int i = 1; i <= n; i++)
		{
			scanf("%d", &p[i]);
			sum += p[i];
		}

		int l = 0, r = maxx, ans = -1;
		while (l <= r)
		{
			int mid = (l + r) >> 1;
			if (check(mid))
			{
				r = mid - 1;
				ans = mid;
			}
			else
			{
				l = mid + 1;
			}
		}
		printf("Case #%d: ", ++cas);
		if (ans == -1) printf("Impossible\n");
		else printf("%d\n", ans);

	}
	return 0;
}



你可能感兴趣的:(OJ_UVA,网络流_最大流,算法_二分/三分,ACM)