链接: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;
}
};