ural Two Rounds(分组背包)

题意:乌拉尔锦标赛分为两轮,每轮有N道题,总共有2*N道题,但是在这些题中,有些题目有相似性,这样的题目是不允许放在同一轮里的,题目要求给出合理的题目分组来。

分析:刚开始想用BFS搜的,在搜的过程中进行染色,但是最后放弃了这个思路,因为这个图极有可能是不连通的,怎样确定每个连通分支起始点的颜色才能找到一个合理的分组来就成为解题的关键,但是这个却没有一个准确的规律可循,所以只能用分组背包。其实就是先进行一遍dfs的深搜,将每个连通分支的点都分为两种颜色,将每个连通分支作为一组,然后进行dp求解。

代码:

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

vector<int>p[N] ;
int mp[N][N] , f[N] ;
int s[N] , num1[N] , num2[N] ;
int n , m ;

void init()
{
    memset( mp , 0 , sizeof( mp )) ;
    memset( num1 , 0 , sizeof ( num1 )) ;
    memset( num2 , 0 , sizeof ( num2 )) ;
    memset( f , 0 , sizeof ( f )) ;
    memset( s , 0 , sizeof( s )) ;
    for ( int i = 0 ; i <= 2 * n ; i++ )
    p[i].clear() ;
}

bool dfs( int x , int id )
{
    if ( f[x] )
    {
        if ( f[x] == id )
        return true ;
        return false ;
    }
    f[x] = id ;
    if ( id > 0 ) num1[id]++ ;
    else
    num2[-id]++ ;

    for ( int i = 0 ; i < p[x].size() ; i++ )
    {
        if ( !dfs( p[x][i] , -id ))
        return false ;
    }
    return true ;
}

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

    while ( scanf ( "%d%d" , &n , &m ) != EOF )
    {
        init() ;

        for ( i = 1 ; i <= m ; i++ )
        {
            scanf ( "%d%d" , &x , &y ) ;
            p[x].push_back( y ) ;
            p[y].push_back( x ) ;
        }
        x = 0 ;
        for ( i = 1 ; i <= 2 * n ; i++ )
        {
            if ( !f[i] )
            {
               if ( !dfs( i , ++x ) )
               break ;
            }
        }
        if ( i <= 2 * n )
        {
            printf ( "IMPOSSIBLE\n" ) ;
            continue ;
        }

        mp[0][0] = 1 ;
        for ( i = 0 ; i <= x ; i++ )
        {
            for ( j = 0 ; j <= n ; j++ )
            {
                if ( mp[i][j] == 0 )
                continue;
                mp[i+1][j+num1[i+1]] = 1 ;
                mp[i+1][j+num2[i+1]] = -1 ;
            }
        }

        if( mp[x][n] == 0 )
        {
            printf ( "IMPOSSIBLE\n" ) ;
        }
        else
        {
            k = n ;
            for ( i = x ; i > 0 ; i-- )
            {
                s[i] = mp[i][k] ;
                if ( mp[i][k] > 0 )
                k -= num1[i] ;
                else
                k -= num2[i] ;
            }

            for ( i = 1 ; i <= 2 * n ; i++ )
            {
                if ( ( f[i] > 0 && s[f[i]] > 0 ) || ( f[i] < 0 && s[-f[i]] < 0 ))
                printf ( "%d " , i ) ;
            }
            printf ( "\n" ) ;
            for ( i = 1 ; i <= 2 * n ; i++ )
            {
                if (!( f[i] > 0 && s[f[i]] == 1 ) && !( f[i] < 0 && s[-f[i]] == -1 ))
                printf ( "%d " , i ) ;
            }
            printf ( "\n" ) ;
        }
    }
    return 0 ;
}
原文地址:https://www.cnblogs.com/misty1/p/2879506.html