【题解】Red-Blue Graph Codeforces 1288F 上下界费用流

特别有趣的一个题。

很容易想到可能是网络流问题,关键在于如何刻画诸如“Red边比Blue边多”这样的限制。

最后我还是看了题解。。。很有趣的思路。

对于每条边,假设她连接了左边点u和右边点v,那么:

  • 从u到v连一条容量是1,费用是r的边,如果走了这条边,意味着这条边染Red。

  • 从v到u连一条容量是1,费用是b的边,如果走了这条边,意味着这条边染Blue。

对于左边的有Red限制的点,显然要求这个点“出去的流量”大于“进来的流量”,因此从这个点连向T,下界是1,上界是INF,费用是0。

其他情况可以比葫芦画瓢推出如何连边,太简单了不写了。

所以是一个上下界的最小费用可行流。

#include <bits/stdc++.h>

using namespace std;
typedef pair<int,int> pii;
const int N = 210;
int _w;

namespace MCMF {
	const int MAXN = 1000010;
	const int MAXM = 1000010;
	
	struct Edge {
		int u, v, c, f, w;
		Edge() {}
		Edge( int uu, int vv, int cc, int ff, int ww ) {
			u = uu, v = vv, c = cc, f = ff, w = ww;
		}
	};
	
	int n, m, s, t;
	int head[MAXN], nxt[MAXM];
	Edge edge[MAXM];
	
	void init( int nn ) {
		n = nn, m = 0;
		for( int i = 0; i < n; ++i )
			head[i] = -1;
	}
	int adde( int u, int v, int c, int w ) {
		int e = m;
		edge[m] = Edge(u, v, c, 0, w);
		nxt[m] = head[u], head[u] = m++;
		edge[m] = Edge(v, u, 0, 0, -w);
		nxt[m] = head[v], head[v] = m++;
		return e;
	}
	
	int res[MAXN], from[MAXN];
	int dis[MAXN];
	bool inq[MAXN];
	queue<int> q;
	
	bool spfa() {
		for( int i = 0; i < n; ++i )
			dis[i] = 1e9;
		dis[s] = 0, inq[s] = 1, q.push(s), res[s] = 1e9;
		while( !q.empty() ) {
			int u = q.front(); q.pop();
			inq[u] = 0;
			for( int i = head[u]; ~i; i = nxt[i] ) {
				Edge &e = edge[i];
				if( e.c > e.f && dis[u] + e.w < dis[e.v] ) {
					dis[e.v] = dis[u] + e.w;
					res[e.v] = min( res[u], e.c-e.f );
					from[e.v] = i;
					if( !inq[e.v] )
						inq[e.v] = 1, q.push(e.v);
				}
			}
		}
		return dis[t] != 1e9;
	}
	void augment() {
		int u = t, f = res[t];
		while( u != s ) {
			int i = from[u];
			edge[i].f += f;
			edge[i^1].f -= f;
			u = edge[i].u;
		}
	}
	pii solve( int ss, int tt ) {
		s = ss, t = tt;
		int flow = 0;
		int cost = 0;
		while( spfa() ) {
			flow += res[t];
			cost += res[t] * dis[t];
			augment();
		}
		return pii(flow, cost);
	}
}

int n1, n2, m, r, b;
char Lcolor[N], Rcolor[N], Ecolor[N];
pii edge[N];
int ans;

int S, T, SS, TT, nid, Lid[N], Rid[N];
int eid_red[N], eid_blue[N];

int add_edge( int u, int v, int l, int r, int w ) {
	int e = MCMF::adde(u, v, r-l, w);
	if( l ) {
		MCMF::adde(SS, v, l, 0);
		MCMF::adde(u, TT, l, 0);
	}
	return e;
}

bool solve() {
	S = nid++, T = nid++, SS = nid++, TT = nid++;
	for( int i = 1; i <= n1; ++i )
		Lid[i] = nid++;
	for( int i = 1; i <= n2; ++i )
		Rid[i] = nid++;
	MCMF::init(nid);
	add_edge(T, S, 0, 1e9, 0);
	int low_sum = 0;
	for( int i = 1; i <= n1; ++i )
		if( Lcolor[i] == 'R' ) {
			add_edge(S, Lid[i], 1, 1e9, 0);
			++low_sum;
		} else if( Lcolor[i] == 'B' ) {
			add_edge(Lid[i], T, 1, 1e9, 0);
			++low_sum;
		} else {
			add_edge(S, Lid[i], 0, 1e9, 0);
			add_edge(Lid[i], T, 0, 1e9, 0);
		}
	for( int i = 1; i <= n2; ++i )
		if( Rcolor[i] == 'R' ) {
			add_edge(Rid[i], T, 1, 1e9, 0);
			++low_sum;
		} else if( Rcolor[i] == 'B' ) {
			add_edge(S, Rid[i], 1, 1e9, 0);
			++low_sum;
		} else {
			add_edge(S, Rid[i], 0, 1e9, 0);
			add_edge(Rid[i], T, 0, 1e9, 0);
		}
	for( int i = 1; i <= m; ++i ) {
		int L = edge[i].first;
		int R = edge[i].second;
		eid_red[i] = add_edge(Lid[L], Rid[R], 0, 1, r);
		eid_blue[i] = add_edge(Rid[R], Lid[L], 0, 1, b);
	}
	pii tmp = MCMF::solve(SS, TT);
	if( tmp.first != low_sum ) return false;
	ans = tmp.second;
	for( int i = 1; i <= m; ++i ) {
		using MCMF::edge;
		int R = eid_red[i];
		int B = eid_blue[i];
		if( edge[R].f && !edge[B].f ) {
			Ecolor[i] = 'R';
		} else if( !edge[R].f && edge[B].f ) {
			Ecolor[i] = 'B';
		} else {
			Ecolor[i] = 'U';
		}
	}
	return true;
}

int main() {
	_w = scanf( "%d%d%d%d%d", &n1, &n2, &m, &r, &b );
	_w = scanf( "%s", Lcolor+1 );
	_w = scanf( "%s", Rcolor+1 );
	for( int i = 1; i <= m; ++i ) {
		_w = scanf( "%d%d", &edge[i].first, &edge[i].second );
	}
	if( solve() ) {
		printf( "%d\n", ans );
		Ecolor[m+1] = 0;
		puts(Ecolor + 1);
	} else {
		puts("-1");
	}
	return 0;
}

posted @ 2020-01-31 22:00  mlystdcall  阅读(340)  评论(1编辑  收藏