zoukankan      html  css  js  c++  java
  • 【题解】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
    ", ans );
    		Ecolor[m+1] = 0;
    		puts(Ecolor + 1);
    	} else {
    		puts("-1");
    	}
    	return 0;
    }
    
    
  • 相关阅读:
    什么是Flex 布局
    wx.navigateTo、wx.redirectTo和wx.switchTab三种导航方式的区别
    Ajax 工作原理 及 实例
    NodeJS之 Express框架 app.use(express.static)
    Parcel 入门 (一)
    打包工具的介绍
    CSS网页布局
    《拖延心理学》阅读要点
    PHP实现页面静态化
    PHP中的魔术方法
  • 原文地址:https://www.cnblogs.com/mlystdcall/p/12246941.html
Copyright © 2011-2022 走看看