ural Mosaic(强连通分支)

题意:幼儿园里有N个盒子,每个盒子有一种颜色,每个盒子中可以装M个与盒子颜色相同的拼图,但是现在有些孩子将拼图放错了盒子,幼儿园老师要将放错的拼图放到正确的盒子里,她每次可以拿一块拼图从这个盒子到另一个盒子,也可以什么都不拿都另一个盒子,问这个老师最少要移动多少次手才能整理好这些拼图。

思路:求强连通分支。首先,在同一个强连通分支里的盒子之间是可以互换的,即颜色A的拼图放到了颜色B的盒子了,那么一定可以从颜色B的盒子里取出A然后放回颜色为A的盒子里,然后从A盒子了取出颜色不为A的拼图放回正确的盒子里,所以最少移动的次数就是放错拼图的个数。如果不是一个强连通分支,那么在整理完这个强连通分支里的盒子后,一定会空手到另一个强连通分支去,最少的移动次数是:放错的拼图数+(强连通分支数-1)。另外还要考虑的是,如果这个盒子的拼图都是正确,那么这个盒子就不能加入图中。

代码:

View Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <queue>
#include <math.h>
#include <stack>
#include <vector>
#include <map>
#define  N 53
#define  M 505
using namespace std ;

bool mp[M][M] ;
int dfn[M] , low[M] ;
bool used[M] , vist[M] , f[M] ;
int id , ans , cnt , n , m ;
stack<int>q ;

void init()
{
    memset( mp , false , sizeof( mp )) ;
    memset( dfn , 0 , sizeof ( dfn )) ;
    memset( low , 0 , sizeof ( low )) ;
    memset( used , false , sizeof( used ));
    memset( vist , false , sizeof ( vist )) ;
    memset( f , false , sizeof ( f )) ;
    id = cnt = ans = 0 ;
    while( !q.empty()) q.pop();
}

void Tarjan( int x )
{
    dfn[x] = low[x] = ++id ;
    used[x] = vist[x] = true ;
    q.push( x ) ;

    for ( int i = 1 ; i <= n ; i++ )
    {
        if ( mp[x][i] )
        {
            if ( !used[i] )
            {
                Tarjan( i ) ;
                low[x] = min( low[x] , low[i] ) ;
            }
            else if ( vist[i] )
            {
                low[x] = min( low[x] , dfn[i] ) ;
            }
        }
    }
    if ( dfn[x] == low[x] )
    {
        ans++ ;
        int u ;
        do
        {
            u = q.top() ;
            q.pop();
            vist[u] = false ;
        }while( u != x ) ;
    }
}

int main()
{
    int i , j , x ;

    while ( scanf ( "%d%d" , &n , &m ) != EOF )
    {
        init() ;
        for ( i = 1 ; i <= n ; i++ )
        {
            for ( j = 1 ; j <= m ; j++ )
            {
                scanf ( "%d" , &x ) ;
                if ( x != i )
                {
                    mp[x][i] = true ;
                    f[i] = true ;
                    cnt++ ;
                }
            }
        }

        /*for ( i = 1 ; i <= n ; i++ )
        {
            for ( j = 1 ; j <= n ; j++ )
            cout<<mp[i][j]<<" ";
            cout<<endl ;
        }*/
        for ( i = 1 ; i <= n ; i++ )
        if ( !dfn[i] && f[i] )
        Tarjan( i ) ;

        //cout<<ans<<endl ;
        cnt = cnt + max( ans - 1 , 0 );

        cout<<cnt<<endl ;
    }
    return 0 ;
}

 

posted @ 2013-01-24 17:14  Misty_1  阅读(227)  评论(0编辑  收藏  举报