标签: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