CodeForces - 730I Olympiad in Programming and Sports(最大费用最小流)

题目大意:

见题面

思路:

一道很普通的mcmf,取一个学生的a值或者b值可以用流量来表示,即每个学生有1的流量。题目中我要求输出对与每个学生的被选择情况,我们可以通过遍历学生的正向边或者反向边的流量得出学生的被选择情况。

Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL N = 3010;
struct node
{
	LL v, flow, cost, next;
}edge[N*N];
LL head[N], dis[N], vis[N], pre[N], rec[N], cnt;
queue<LL> q;
inline void init()
{
	cnt = 0;
	memset(head, -1, sizeof(head));
}
inline void add_edge(LL u, LL v, LL f, LL c)
{
	edge[cnt].v = v; edge[cnt].flow = f; edge[cnt].cost = c;
	edge[cnt].next = head[u]; head[u] = cnt++;
	edge[cnt].v = u; edge[cnt].flow = 0; edge[cnt].cost = -c;
	edge[cnt].next = head[v]; head[v] = cnt++;
}
LL SPFA(LL s, LL t)
{
	memset(dis, 0x3f, sizeof dis);
	memset(vis, 0, sizeof vis);
	while(!q.empty()) q.pop();
	q.push(s); dis[s] = 0; vis[s] = 1;
	while(!q.empty())
	{
		LL tp = q.front(); q.pop();
		vis[tp] = 0;
		LL k = head[tp];
		while(k != -1)
		{
			if(dis[edge[k].v] > dis[tp] + edge[k].cost && edge[k].flow)
			{
				dis[edge[k].v] = dis[tp] + edge[k].cost;
				pre[edge[k].v] = tp; rec[edge[k].v] = k;
				if(vis[edge[k].v] == 0)
				{
					vis[edge[k].v] = 1;
					q.push(edge[k].v);
				}
			}
			k = edge[k].next;
		}
	}
	if(dis[t] == INF) return 0;
	return 1;
}
pair<LL, LL> Mcmf(LL s, LL t)
{
	LL minflow, k, mincost = 0, maxflow = 0;
	while(SPFA(s, t))
	{
		k = t; minflow = INF;
		while(k != s)
		{
			minflow = min(minflow, edge[rec[k]].flow);
			k = pre[k];
		}
		k = t; maxflow += minflow;
		while(k != s)
		{
			mincost += minflow*edge[rec[k]].cost;
			edge[rec[k]].flow -= minflow;
			edge[rec[k]^1].flow += minflow;
			k = pre[k];
		}
	}
	return make_pair(maxflow, mincost);
}

LL a[N], b[N];
vector<LL> qa;
vector<LL> qb;

int main()
{
	init(); // do not forget it
	LL n, m, s, t, pp, ps, valp, vals;
	cin >> n >> valp >> vals;
	s = 0;
	pp = n + 1;
	ps = n + 2;
	t = n + 3;
	for (LL i = 1; i <= n; i++) cin >> a[i];
	for (LL i = 1; i <= n; i++) cin >> b[i];
	for (LL i = 1; i <= n; i++) {
		add_edge(s, i, 1, 0);
		add_edge(i, pp, 1, -a[i]);
		add_edge(i, ps, 1, -b[i]);
	}
	add_edge(pp, t, valp, 0);
	add_edge(ps, t, vals, 0); 
	pair<LL, LL> ans = Mcmf(s, t);
	cout << -1LL * ans.second << endl;
	for (LL i = 1; i <= n; i++) {
		for (LL j = head[i]; ~j; j = edge[j].next) {
			// if (edge[j].flow) continue; //not be used
                        if(!edge[j ^ 1].flow) continue; //反向边没有流量,说明正向边没有被使用
			if (edge[j].v == pp) qa.push_back(i);
			if (edge[j].v == ps) qb.push_back(i);
		}
	}
	for (auto i : qa) cout << i << " ";
	cout << endl;
	for (auto i : qb) cout << i << " ";
	cout << endl;
	return 0;
}
上一篇:[Algorithm] Max icons to include: Dynamic programming


下一篇:查找书籍 (10分)(PTA)