说在前面
感觉me变得颓废了…
闲得去看别人的NOI游记了…
以前总是觉得「和别人比高低、被催促着学习、不学就会落后」这样的感觉差极了
然而me现在才慢慢的感受到…竞争才能跑得更快
题目
BZOJ1937传送门
看题可戳传送门
解法
me记得me曾经用单纯形法水过了这道题emmmm
首先一个显然的事实:树边的权值只会减少,非树边的权值只会增加
然后我们相当于是要满足这个条件:任何一条非树边与这个树构成的环,非树边的权值最大
记
为第
条边的权值,
为改变量
然后就是要
,其中
是树边,
是非树边。我们的目的是要最小化:
移项变成了:
然后这就是一个线性规划的式子,直接单纯形暴力做就好了
然后我们发现,这个式子很像KM算法中对于顶标的定义,要求的东西也正好是KM算法的意义
所以直接用KM算法解决这道题
题外话:其实不难发现,最大权匹配也是线性规划的一种
下面是代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N , M , ide[55][55] , head[55] , tp ;
struct Edge{
int u , v , w ;
bool intree ;
} e[855] ;
struct Path{
int pre , to ;
} p[1655] ;
template < typename T > void smax( T &x , T y ){ if( x < y ) x = y ; }
template < typename T > void smin( T &x , T y ){ if( x > y ) x = y ; }
void In( int t1 , int t2 ){
p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
p[++tp] = ( Path ){ head[t2] , t1 } ; head[t2] = tp ;
}
bool vy[805] , vx[805] ;
int macy[805] , macx[805] , que[805] , fr , ba , lac[805] , pre[805] ;
int dep[805] , fa[805] , w[805][805] , lx[805] , ly[805] ;
void dfs( int u , int f ){
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( v == f ) continue ;
dep[v] = dep[u] + 1 ;
fa[v] = u , dfs( v , u ) ;
}
}
void Jump( int u , int v , int id ){
while( u != v ){
if( dep[u] < dep[v] ) swap( u , v ) ;
int id2 = ide[ fa[u] ][u] ;
w[id2][id] = e[id2].w - e[id].w ;
u = fa[u] ;
}
}
void preWork(){
dfs( 1 , 1 ) ;
for( int i = 1 ; i <= M ; i ++ )
if( !e[i].intree ) Jump( e[i].u , e[i].v , i ) ;
for( int i = 1 ; i <= M ; i ++ )
for( int j = 1 ; j <= M ; j ++ )
smax( lx[i] , w[i][j] ) ;
}
void match( int v ){
while( v ){
macy[v] = pre[v] ;
swap( v , macx[ pre[v] ] ) ;
}
}
void BFS( int St ){
fr = 1 , que[ ba = 1 ] = St , vx[St] = true ;
while( true ){
while( ba >= fr ){
int u = que[fr++] , tmp ;
for( int v = 1 ; v <= M ; v ++ ){
tmp = lx[u] + ly[v] - w[u][v] ;
if( vy[v] || tmp >= lac[v] ) continue ;
pre[v] = u ;
if( !tmp ){
if( !macy[v] ) return match( v ) ;
vy[v] = vx[ macy[v] ] = true ;
que[++ba] = macy[v] ;
} else lac[v] = tmp ;
}
} int rem = 0x3f3f3f3f , v ;
for( int i = 1 ; i <= M ; i ++ )
if( !vy[i] && rem > lac[i] ) rem = lac[i] , v = i ;
if( rem == 0x3f3f3f3f ) return ;
for( int i = 1 ; i <= M ; i ++ ){
if( vx[i] ) lx[i] -= rem ;
if( vy[i] ) ly[i] += rem ;
else lac[i] -= rem ;
} if( !macy[v] ) return match( v ) ;
vy[v] = vx[ macy[v] ] = true , que[++ba] = macy[v] ;
}
}
void solve(){
for( int i = 1 ; i <= M ; i ++ ) if( !macx[i] ){
memset( vx , 0 , sizeof( vx ) ) ;
memset( vy , 0 , sizeof( vy ) ) ;
memset( lac , 0x3f , sizeof( lac ) ) ;
BFS( i ) ;
} long long ans = 0 ;
for( int i = 1 ; i <= M ; i ++ )
ans += lx[i] + ly[i] ;
printf( "%lld\n" , ans ) ;
}
int main(){
scanf( "%d%d" , &N , &M ) ;
for( int i = 1 , u , v , w ; i <= M ; i ++ ){
scanf( "%d%d%d" , &u , &v , &w ) ;
e[i] = ( Edge ){ u , v , w , 0 } ;
ide[u][v] = ide[v][u] = i ;
} for( int i = 1 , u , v ; i < N ; i ++ ){
scanf( "%d%d" , &u , &v ) , In( u , v ) ;
e[ ide[u][v] ].intree = true ;
} preWork() ; solve() ;
}