poj 3592 Instantaneous Transference(强连通分支 +spfa)

题意:给出一个N*M的矩形,每个小矩形里有的有一定数量的矿物,有的有传输的功能,有的不能通过,每个小矩形里的矿物只能采集一次,问你最多能过采集多少的矿物。

思路:强连通分支+spfa,先求出强连通分支,在强连通分支中,所以点都是可达的,然后进行缩点,将每一个连通分支看做一个点,而这个点的矿物容量就是这个强连通分支中所有点的和,然后在用一下spfa求最大的矿物量。

PS:因为没注意一个循环的长度,导致我查了一个下午加一个晚上,泪~~,细心!细心啊!

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
#define N 2004
#define M 50
#define T 200020
using namespace std ;

struct node
{
    int u ;
    int v ;
    int val ;
    int next ;
}p[T] , d[T] ;

int head1[N] , head2[N] ;
int dfn[N] , low[N] ;
int dis[N] , vist[N] ;
int belong[N] , sum[N] , valx[N] ;
int st[N] , q[N] , f[N] ;
int n , m , cnt , num1 , num2 , res , index , all ;
int top ;

void add( int x , int y )
{
    p[num1].u = x ;
    p[num1].v = y ;
    p[num1].next = head1[x] ;
    head1[x] = num1++ ;
}

void add2( int  x , int y , int c )
{
    d[num2].u = x ;
    d[num2].v = y ;
    d[num2].val = c ;
    d[num2].next = head2[x] ;
    head2[x] = num2++ ;
}

int min( int x , int y )
{
    return x < y ? x : y ;
}

void dfs( int x )
{
    int y , u ;

    dfn[x] = low[x] = index++ ;
    st[top++] = x ;
    f[x] = 1;
    for ( y = head1[x] ; y != -1 ; y = p[y].next )
    {
        u = p[y].v ;
        if ( !dfn[u] )
        {
            dfs( u ) ;
            low[x] = min( low[x] , low[u] );
        }
        else if ( f[u] )
        low[x] = min( low[x] , dfn[u] ) ;
    }
    if ( dfn[x] == low[x] )
    {
        res++ ;
        do
        {
            y = st[--top] ;
            f[y] = 0 ;
            belong[y] = res ;
        }while( y != x ) ;
    }
}

void Tarjan()
{
    int i ;
    memset( dfn , 0 , sizeof( dfn ));
    memset( low , 0 , sizeof( low ));
    memset( st , 0 , sizeof ( st ));
    memset( f , 0 , sizeof ( f )) ;
    top = 0 ;index = 1 ;res = 0 ;
    for ( i = 0 ; i < all ; i++ )
    if ( !dfn[i] )
    dfs( i );

    memset( sum , 0 , sizeof ( sum )) ;
    for ( i = 0 ; i < all ; i++ )
    sum[belong[i]] += valx[i] ;
}

void slove( int s )
{
    int x , y ;
    int len = res + 1 ;
    memset( q , 0 , sizeof( q ));
    for( x = 0 ; x < len ; x++ )
    {
        dis[x] = -1 ;
        vist[x] = 0 ;
    }
    dis[s] = 0 ;
    //vist[s] = 1 ;
    int head = 0 ;
    int tail = 0 ;
    q[head++] = s ;

    while( head != tail )
    {
        x = q[tail++] ;
        vist[x] = 0 ;
        if ( tail == N ) tail = 0 ;
        for ( y = head2[x] ; y != -1 ;  y = d[y].next )
        {
            int v = d[y].v ;
            if ( dis[v] < dis[x] + d[y].val )
            {
                dis[v] = dis[x] + d[y].val ;
                if( !vist[v] )
                {
                    vist[v] = 1 ;
                    q[head++] = v ;
                    if ( head == N ) head = 0 ;
                }
            }
        }
    }
}

int spfa()
{
    int i , j ;
    num2 = 2 ;
    memset( head2 , -1 , sizeof( head2 )) ;
    add2( 0 , belong[0] , sum[belong[0]] ) ;
    for ( i = 0 ; i < all ; i++ )
    {
        for ( j = head1[i] ; j != -1 ; j = p[j].next )
        {
            int v = p[j].v ;
            if ( belong[i] != belong[v] )
            add2( belong[i] , belong[v] , sum[belong[v]] );
        }
    }
    slove( 0 );

    int maxx = 0 ;
    for ( i = 1 ; i <= res ; i++ )
    if ( dis[i] > maxx )
    maxx = dis[i] ;
    return maxx ;
}

void work()
{
    int i , j , r , c , k ;
    char str[M][M] ;
    int data[M][M] , pos[N] ;
    int dir[2][2] = {{-1, 0} , {0 ,-1}} ;

    all = 0 ; num1 = 2 ;k = 0 ;
    memset( head1 , -1 , sizeof ( head1 ));
    scanf( "%d%d" , &n , &m ) ;
    for ( i = 0 ; i < n ; i++ )
    {
        scanf ( "%s" , str[i] );
        for ( j = 0 ; j < m ; j++ )
        {
            if ( str[i][j] == '#' )
            continue ;
            data[i][j] = all++ ;
            if ( str[i][j] >= '0' && str[i][j] <= '9')
            {
                valx[data[i][j]] = str[i][j] - '0' ;
            }
            else
            {
                valx[data[i][j]] = 0 ;
            }

            if ( str[i][j] == '*' )
            {
                pos[k++] = data[i][j] ;
            }
            for ( int xx = 0 ; xx < 2 ; xx++ )
            {
                r = i + dir[xx][0] ;
                c = j + dir[xx][1] ;
                if( r >= 0 && c >= 0 )
                {
                    if ( str[r][c] == '#' )
                    continue ;
                    add( data[r][c] , data[i][j] );
                }
            }
        }
    }
    for ( i = 0 ; i < k ; i++ )
    {
        scanf ( "%d%d" , &r , &c ) ;
        if ( str[r][c] == '#' )
        continue ;
        add( pos[i] , data[r][c] );
    }
    Tarjan();

    int ans = spfa( );
    printf ( "%d\n" , ans );
}

int main()
{
    int cas ;

    scanf( "%d" , &cas );
    while ( cas-- )
    {
        work();
    }
    return 0 ;
}
原文地址:https://www.cnblogs.com/misty1/p/2615581.html