Topcoder 2016 TCO Algorithm Algo Semifinal 1 Hard

链接:https://community.topcoder.com/stat?c=problem_statement&pm=14447&rd=16839

题意:给一个DAG图,记边是从a[i]到b[i],边权c[i],要从0走到n,求最短路。

保证a[i] < b[i],而且不存在a[i] < a[j] < b[i] < b[j]

每个点有一个颜色,每种颜色在路径上要么不经过,要么全部经过

题解:

网络流

认真观察可以发现这些边对应的区间构成了树的形式

我们考虑用最小割解决这道题

假设当前考虑区间[l, r],表示节点为fa,则对于每个分割点[a, b],表示节点为x,连边(fa, x, c(a, b))

树叶向T连INF的边,画一画就知道一个割对应一条路径。

现在考虑颜色,每个father记录子节点的颜色,被放进对应颜色的vector里,然后两两连INF的边,树上向上加INF的反向边

这样保证了每种颜色的点要么都在S集,要么都在T集

#include <bits/stdc++.h>
#define xx first
#define yy second
#define mp make_pair
#define pb push_back
#define fill( x, y ) memset( x, y, sizeof x )
#define copy( x, y ) memcpy( x, y, sizeof x )
using namespace std;

typedef long long LL;
typedef pair < int, int > pa;

const int MAXN = 5005;
const int MAXM = 500005;
const int INF = 0x3f3f3f3f;

int cnt = 1, n, c[MAXN];
vector < int > r[MAXN], w[MAXN], col[MAXN];

namespace Flow
{
	struct edge { int to, nxt, flow; } e[MAXM];

	int head[MAXN], cur[MAXN], S, T = 1, e_cnt = 1, q[MAXN], ql, qr, dis[MAXN];

	inline void Add(int x, int y, int w) { e[ ++e_cnt ] = { y, head[ x ], w }; head[ x ] = e_cnt; }
	inline void Addedge(int x, int y, int w) { Add( x, y, w ); Add( y, x, 0 ); }

	inline bool Bfs()
	{
		for( int i = 0 ; i <= cnt ; i++ ) dis[ i ] = 0;
		dis[ q[ ql = 0 ] = S ] = qr = 1;
		while( ql < qr )
		{
			int x = q[ ql++ ];
			for( int i = head[ x ] ; i ; i = e[ i ].nxt )
				if( e[ i ].flow && !dis[ e[ i ].to ] ) dis[ q[ qr++ ] = e[ i ].to ] = dis[ x ] + 1;
		}
		return dis[ T ];
	}

	inline int Dfs(int x, int f)
	{
		if( x == T ) return f;
		int ret = 0;
		for( int &i = cur[ x ] ; i ; i = e[ i ].nxt )
			if( e[ i ].flow && dis[ e[ i ].to ] == dis[ x ] + 1 )
			{
				int d = Dfs( e[ i ].to, min( f - ret, e[ i ].flow ) );
				ret += d; e[ i ].flow -= d; e[ i ^ 1 ].flow += d;
				if( ret == f ) return ret;
			}
		if( !ret ) dis[ x ] = -1;
		return ret;
	}

	inline int Dinic()
	{
		int ret = 0;
		while( Bfs() ) memcpy( cur, head, sizeof head ), ret += Dfs( S, INF ), ret = min( ret, INF );
		return ret;
	}
}

using Flow::Addedge;
using Flow::S;
using Flow::T;
using Flow::Dinic;

class ColorfulPath
{
	public:
		inline void build(int L, int R, int fa)
		{
			for( int x = L ; x < R ; )
			{
				int d = 0, y = 0, m = r[ x ].size();
				if( x ^ L ) col[ c[ x ] ].pb( fa );
				for( int i = 0 ; i < m ; i++ ) if( r[ x ][ i ] > y ) y = r[ x ][ i ], d = i;
				if( !y )
				{
					Addedge( fa, T, INF );
					for( int i = L + 1 ; i < R ; i++ ) col[ c[ i ] ].pb( fa );
					return ;
				}
				else
				{
					r[ x ][ d ] = 0;
					cnt++;
					Addedge( fa, cnt, w[ x ][ d ] ); Addedge( cnt, fa, INF );
					build( x, y, cnt );
					x = y;
				}
			}
		}

		int shortestPath(vector < int > a, vector < int > b, vector < int > cost, vector < int > color)
		{
			n = color.size() + 1; int m = a.size();
			for( int i = 0 ; i < m ; i++ ) r[ a[ i ] ].pb( b[ i ] ), w[ a[ i ] ].pb( cost[ i ] );
			for( int i = 1 ; i < n ; i++ ) c[ i ] = color[ i - 1 ];
			build( 0, n, S );
			for( int i = 1 ; i <= 1000 ; i++ )
			{
				m = col[ i ].size();
				for( int j = 1 ; j < m ; j++ ) Addedge( col[ i ][ j ], col[ i ][ j - 1 ], INF ), Addedge( col[ i ][ j - 1 ], col[ i ][ j ], INF );
			}
			int ans = Dinic();
			if( ans >= INF ) ans = -1;
			return ans;
		}
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值