码迷,mamicode.com
首页 > 其他好文 > 详细

UVA 10817 Headmaster's Headache

时间:2016-12-17 07:42:40      阅读:199      评论:0      收藏:0      [点我收藏+]

标签:div   ast   names   记忆化搜索   max   dac   int   namespace   continue   

题解:

状压dp + 01背包

除了每个教师外,每个求职者可选可不选。这就相当于01背包

只不过把状态的表示变成的二进制的形式

该题有3个状态

1.没人教的课程

2.只有一人教的课程 s1

3.至少两个人教的课程 s2

因为是至少2个人教,无法从第3个状态转换到第2个状态。但是很容易从第二个状态转到第3个状态,那么如果从第一个状态转化到第二状态?

int t = ( ( 1 << s ) - 1 ) ^ ( j | k );

int m1 = st[ i ] & t, m2 = st[ i ] & j;

t 表示s1和s2都没有的课程。

m1 表示 求职者教的课程中有多少在t中,方便从没人教的课程到只有一个人教的课程

m2 表示 在只有一个人教的课程中,求职者可以教的课程。方便转化到至少2个人教的课程

代码:

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fs first
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define ll long long

const int maxn = 100 + 20 + 5;
const int maxs = 8;
const int INF = 100000000;

int n, m, s;
int c[ maxn ], st[ maxn ], dp[ maxn ][ 1 << maxs ][ 1 << maxs ];


int main()
{
    int x;
    string line;
    while( getline( cin,line ) )
    {
        stringstream ss( line );
        ss >> s >> m >> n;
        if( s == 0 ) break;
        for( int i = 1; i <= m + n; i ++ )
        {
            getline( cin, line );
            stringstream ss( line );
            ss >> c[ i ];
            st[ i ] = 0;
            while( ss >> x ) st[ i ] |= ( 1 << ( x - 1 ) );
        }
        memset( dp, 0x3f, sizeof( dp ) );
        dp[ 0 ][ 0 ][ 0 ] = 0;
        for( int i = 1; i <= n + m; i ++ )
        {
            for( int j = 0; j < ( 1 << s ); j ++ )
            for( int k = 0; k < ( 1 << s ); k ++ )
            {
                if( j & k ) continue;
                if( i > m ) dp[ i ][ j ][ k ] = min( dp[ i ][ j ][ k ], dp[ i - 1 ][ j ][ k ] );
                int t = ( ( 1 << s ) - 1 ) ^ ( j | k );
                int m1 = st[ i ] & t, m2 = st[ i ] & j;
                dp[ i ][ ( j | m1 ) ^ m2 ][ k | m2 ] = min( dp[ i ][ ( j | m1 ) ^ m2 ][ k | m2 ], dp[ i - 1 ][ j ][ k ] + c[ i ] );
            }
        }
        printf( "%d\n", dp[ n + m ][ 0 ][ ( 1 << s ) - 1 ] );
    }
    return 0;
}

因为有很多无用状态,所以记忆化搜索时间效率高些

#include<bits/stdc++.h>
using namespace std;
#define pb push_back
#define mp make_pair
#define se second
#define fs first
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define ll long long

const int maxn = 100 + 20 + 5;
const int maxs = 8;
const int INF = 100000000;

int n, m, s;
int c[ maxn ], st[ maxn ], d[ maxn ][ 1 << maxs ][ 1 << maxs ];

int dp( int i, int s0, int s1, int s2 )
{
    if( i == m + n ) return s2 == ( 1 << s ) - 1? 0 : INF;
    int& ans = d[ i ][ s1 ][ s2 ];
    if( ans >= 0 ) return ans;
    ans = INF;
    if(  i >= m ) ans = dp( i + 1, s0, s1, s2 );
    int m0 = st[ i ] & s0, m1 = st[ i ] & s1;
    s0 ^= m0;
    s1 = ( s1 ^ m1 ) | m0;
    s2 |= m1;
    ans = min( ans , c[ i ] + dp( i + 1, s0, s1, s2 ) );
    return ans;
}

int main()
{
    int x;
    string line;
    while( getline( cin, line ) )
    {
        stringstream ss ( line );
        ss >> s >> m >> n;
        if( s == 0 ) break;
        for( int i = 0; i < m + n; i ++ )
        {
            getline( cin, line );
            stringstream ss ( line );
            ss >> c[ i ];
            st[ i ] = 0;
            while( ss >> x )  st[ i ] |= ( 1 << ( x - 1 ) );
        }
        memset( d, -1, sizeof( d ) );
        cout << dp( 0, ( 1 << s ) - 1, 0, 0 ) << endl;
    }
    return 0;
}

 

UVA 10817 Headmaster's Headache

标签:div   ast   names   记忆化搜索   max   dac   int   namespace   continue   

原文地址:http://www.cnblogs.com/byene/p/6189034.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!