说在前面
这题的数据…如果luogu上的数据就是当年的官方数据,未免也太水了一点…
me在fix_dfs函数里误调用了dfs函数,居然还能得80分???
(这个小错误me肉眼始终没看出来,然后随便造了一组数据me就WA了…有意思)
题目
BZOJ1565传送门
这题,不是很难,而且概括了题面就没什么意思了233
看题可戳传送门
解法
把样例的依赖关系画出来,立刻就可以知道这个题的做法了
可以发现这是一个,要想选当前格子,就必须先把指向它的格子先选中,把箭头反过来这就是一个闭合子图嘛,然后就是最大权闭合子图了。当然还没完,如果图里面出现了一个环,说明僵尸无论先进哪个格子都会死,那么这个环都不能选,并且这个环指向的格子也全都不能选。于是要给这些不能选的格子打上flag,这一步用tarjan和toposort都可以做到。
这道题就做完了
下面是自带大常数的代码
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
const int inf = 0x3f3f3f3f ;
bool flag[605] ;
int N , M , stp , shead[605] , score[605] , ind[605] ;
int tp = 1 , head[605] , maxn , S , T ;
struct Path{
int pre , to , flow ;
}sp[360005] , p[360005] ;
int code( int i , int j ){ return i * M + j + 1 ; }
pair<int,int> decode( int x ){ return make_pair( ( x-1 )/M , ( x-1 )%M ) ;}
void sIn( int t1 , int t2 ){
sp[++stp] = ( Path ){ shead[t1] , t2 , 0 } ;
shead[t1] = stp ;
}
void In( int t1 , int t2 , int t3 ){
p[++tp] = ( Path ){ head[t1] , t2 , t3 } ;
head[t1] = tp ;
}
int sta[605] , topp ;
int dfn[605] , dfs_c , scc[605] , scc_cnt ;
int dfs( int u ){
sta[++topp] = u ;
int lowu = dfn[u] = ++dfs_c ;
for( int i = shead[u] ; i ; i = sp[i].pre ){
int v = sp[i].to ;
if( !dfn[v] ) lowu = min( lowu , dfs( v ) ) ;
else if( !scc[v] ) lowu = min( lowu , dfn[v] ) ;
}
if( lowu == dfn[u] ){
scc_cnt ++ ;
int tmp = topp ;
while( 1 ){
int x = sta[topp--] ;
scc[x] = scc_cnt ;
if( x == u ) break ;
}
if( tmp - topp > 1 )
for( int i = topp + 1 ; i <= tmp ; i ++ )
flag[ sta[i] ] = true ;
} return lowu ;
}
void fix_dfs( int u ){
flag[u] = true ;
for( int i = shead[u] ; i ; i = sp[i].pre )
if( !flag[ sp[i].to ] ) fix_dfs( sp[i].to ) ;
}
int dis[605] , que[605] , fr , ba ;
bool BFS(){
memset( dis , -1 , sizeof( dis ) ) ;
fr = 1 , ba = 0 ;
dis[S] = 0 ; que[++ba] = S ;
while( fr <= ba ){
int u = que[fr++] ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to ;
if( dis[v] != -1 || !p[i].flow ) continue ;
dis[v] = dis[u] + 1 ;
que[++ba] = v ;
}
} return dis[T] != -1 ;
}
int dfs( int u , int flow ){
if( u == T || !flow ) return flow ;
int rt = 0 ;
for( int i = head[u] ; i ; i = p[i].pre ){
int v = p[i].to , nowf ;
if( dis[v] != dis[u] + 1 || !p[i].flow ) continue ;
nowf = dfs( v , min( flow , p[i].flow ) ) ;
if( nowf ){
rt += nowf ;
flow -= nowf ;
p[i].flow -= nowf ;
p[i^1].flow += nowf ;
if( !flow ) break ;
}
} if( !rt ) dis[u] = -1 ;
return rt ;
}
void solve(){
S = maxn + 1 , T = S + 1 ;
for( int i = maxn ; i ; i -- )
if( !dfn[i] ) dfs( i ) ;
for( int i = maxn ; i ; i -- )
if( flag[i] ) fix_dfs( i ) ;
int ans = 0 ;
for( int u = 1 ; u <= maxn ; u ++ ){
if( flag[u] ) continue ;
if( score[u] > 0 ){
ans += score[u] ;
In( S , u , score[u] ) ;
In( u , S , 0 ) ;
} else {
In( u , T , -score[u] ) ;
In( T , u , 0 ) ;
} for( int i = shead[u] ; i ; i = sp[i].pre ){
int v = sp[i].to ;
if( !flag[v] ){
In( v , u , inf ) ;
In( u , v , 0 ) ;
}
}
}
while( BFS() )
ans -= dfs( S , inf ) ;
printf( "%d" , ans ) ;
}
int main(){
scanf( "%d%d" , &N , &M ) ; maxn = N * M ;
for( int i = 0 ; i < N ; i ++ ){
for( int j = 0 , w ; j < M ; j ++ ){
int now = code( i , j ) ;
scanf( "%d%d" , &score[now] , &w ) ;
for( int k = 1 , li , co ; k <= w ; k ++ ){
scanf( "%d%d" , &li , &co ) ;
sIn( now , code( li , co ) ) ;
}
if( j ) sIn( now , now - 1 ) ;
}
}
solve() ;
}