10817 - Headmaster's Headache(校长的烦恼)

经典的状态压缩DP 。

根据DP的阶段定义,我们需要枚举每一个教师进行递推,但是由于每个教师可以教授的课程是复杂多样的,所以使得状态变得难以转移 。那么要怎么样表示状态呢? 显然增加一两个维度是无法胜任的,所以我们可以用二进制枚举子集的方法,用一个整数通过位运算充当一个集合 。 C++提供的位运算符极像对集合的操作,我们恰好可以利用这一点 。

用d[i][s1][s2]表示考虑了前i个人时的最小花费 。 其中s1表示恰有一个人教的科目集合,s2表示至少有两个人教的科目集合 。因为由这两个量就可以推出一个人也没有教的科目集合,所以用这两个量已经可以表示所有状态了。  然后就是各种精彩的位运算操作 ,代码中最难的部分大概就是这两行位运算 :

int m0 = st[i] & s0, m1 = st[i] & s1;
s0 ^= m0; s1 = (s1 ^ m1) | m0; s2 |= m1;

既然要选择当前这名教师,那么他所教的课程就要使得集合改变 。  m0就是指他能教而且当前没有人教的课 ,m1指他能教且当前只有一个人教的课 。 ^运算符使得相同的为0,不同的为1 ,所以使得那些他能教的课在集合s0中变成了0 ,也就是说这些课升级为恰有一人教的课。  那么显然还要更新s1,(s1 ^ m1)和前面说的作用一样,使得这些课升级为至少有两个人教的,但是别忘了还有一些课升级为恰有一人教的,所以用|(或)操作,将这些课加进s1 中,  s2当然也要加进s1中升级的元素

位运算不但节省空间,而且节省时间, 所以多花一些时间练习用位运算写代码还是很值得的 。

#include<bits/stdc++.h>
using namespace std;
const int INF = 100000000;
int s,n,m,a,c[125],st[125],d[125][1<<8][1<<8];
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() {
    while(~scanf("%d%d%d",&s,&m,&n)&&s) {
        memset(d,-1,sizeof(d));
        for(int i=0;i<m+n;i++) {
            scanf("%d",&c[i]);
            st[i] = 0;
            while(true) {
                scanf("%d",&a);
                a--; st[i] = st[i] | (1 << a);//将该元素加入集合中
                char c = getchar();
                if(c == 10) break;//换行的ascii码
            }
        }
        int ans = dp(0,(1<<s)-1,0,0) ;
        printf("%d\n",ans);
    }
    return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

10817 - Headmaster's Headache(校长的烦恼)

时间: 2024-08-08 13:58:15

10817 - Headmaster's Headache(校长的烦恼)的相关文章

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

UVA 10817 - Headmaster&#39;s Headache

题目:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=20&page=show_problem&problem=1758 状态压缩的DP,dp[i][st]表示状态为st考虑后面i个人所有人最小花费, 因为每个科目有三种状态,可以用一个三进制数表示, 状态不是很多,所以可以把预先把每个数的三进制预处理出来, 决策为选和不选. #include<bits/std

UVA 10817 Headmaster&#39;s Headache 状压DP

记录两个状态S1,S2分别记录哪些课程被1个人教过或2个人教过,然后记忆化搜索 UVA - 10817 Headmaster's Headache Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem D: Headmaster's Headache Time limit: 2 seconds The headmaster of Spr

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje

Uva 10817 Headmaster&#39;s Headache (DP+ 状态压缩)

Problem D: Headmaster's Headache Time limit: 2 seconds The headmaster of Spring Field School is considering employing some new teachers for certain subjects. There are a number of teachers applying for the posts. Each teacher is able to teach one or

状压DP UVA 10817 Headmaster&#39;s Headache

题目传送门 1 /* 2 题意:学校有在任的老师和应聘的老师,选择一些应聘老师,使得每门科目至少两个老师教,问最少花费多少 3 状压DP:一看到数据那么小,肯定是状压了.这个状态不好想,dp[s1][s2]表示s1二进制表示下至少有1位老师的科目集合 4 s2表示至少有2位老师的科目集合所花费的最小金额,状态转移方程(01):dp[t1][t2]=min(dp[t1][t2],dp[j][k]+c[i]); 5 j,k为当前两个集合,t1,t2为转移后的集合,另外求t1,t2用到了& |位运算

UVA - 10817 Headmaster&#39;s Headache (状压类背包dp+三进制编码)

题目链接 题目大意:有S门课程,N名在职教师和M名求职者,每名在职教师或求职者都有自己能教的课程集合以及工资,要求花费尽量少的钱选择一些人,使得每门课程都有至少两人教.在职教师必须选. 可以把“每个课程已经分别有几个人教”作为状态来进行转移,每个人能教的课程集合作为“物品重量”,工资作为“价值”来更新dp值,类似01背包,每放进一个人,从后往前更新即可. 状态的表示可以用三进制编码,为了写起来舒服,我写了个结构体作为状态和编码转换的桥梁,也可以进行状态的“加法运算”,虽然速度比较慢就是了~~ 有

UVa 10817 (状压DP + 记忆化搜索) Headmaster&#39;s Headache

题意: 一共有s(s ≤ 8)门课程,有m个在职教师,n个求职教师. 每个教师有各自的工资要求,还有他能教授的课程,可以是一门或者多门. 要求在职教师不能辞退,问如何录用应聘者,才能使得每门课只少有两个老师教而且使得总工资最少. 分析: 因为s很小,所以可以用状态压缩. dp(i, s1, s2)表示考虑了前i个人,有一个人教的课程的集合为s1,至少有两个人教的集合为s2. 在递归的过程中,还有个参数s0,表示还没有人教的科目的集合. 其中m0, m1, s0, s1, s2的计算用到位运算,还

UVA 10817 十一 Headmaster&#39;s Headache

Headmaster's Headache Time Limit:3000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 10817 1 #include <stdio.h> 2 #include <string.h> 3 #include <algorithm> 4 using namespace std; 5 const int inf=1e