UVA10817 校长的烦恼 Headmaster's Headache

UVA10817 校长的烦恼 Headmaster's Headache

题意:

一开始有一些老师,又来了一些申请者

每个老师能教一个或多个科目 校长想要选择一些申请者以保证每个科目都至少有两名老师能教 同时总共花的钱要最小。

分析:

一眼状压 \(dp\) .

我们考虑压缩科目,设置 \(dp[i][s0][s1][s2]\) ,分别表示:枚举第 \(i\) 个人,没有人教的课,有一个人教,有俩人教。

此时,我们思考一下,如果当前人能教的课程状态为 \(st[i]\) ,那么我们应该怎么转移下一次 \(dp\) 的状态:

一开始 \(s0=1111..1\) ,表示不会的课程

给出代码:

int m0=s0&st[i]; // (别人都不会&i会的)= i目前会的
int m1=s1&st[i]; //  (有一个人会+i会)= 俩人都会的

s0=s0^m0;/// 在没人会的集合里面去除i会的

s1=(s1^m1)|m0;//现在有不会的
//先异或找到俩人同时会的,然后再 | m0表示至少有一个人会的

s2=s2|m1;//至少有两人的情况
//(因为它|的是已经有俩人会的情况,所以1表示就是有俩人会)

那么就很好写了,给出代码:

// UVA10817 校长的烦恼
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3f3f3f3f;
string str;
int s,n,m,val[155],st[155];
int dp[155][1<<8][1<<8];
int dfs(int i,int s0,int s1,int s2){
    if(i==n+m){
        return s2 == (1 << s) - 1 ? 0 : inf;
    }
    int &res=dp[i][s1][s2];
    if(res>=0) return res;
    res=inf;
    if(i>=m) res=dfs(i+1,s0,s1,s2);
    int m0=st[i]&s0;///别人都不会 + i会
    int m1=st[i]&s1;///只有一个人会 + i会
    s0=s0^m0;///在没人会的集合里面去除i会的
    s1=(s1^m1)|m0;//现在有不会的
    s2=s2|m1;//至少有两人的情况(因为它|的是已经有俩人会的情况,所以1表示就是有俩人会)
    res=min(res,dfs(i+1,s0,s1,s2)+val[i]);
    return res;
}
int main(){
    while(getline(cin,str)){
        stringstream ss;
        ss<<str; ss>>s>>m>>n; if(!s) break;
        for(int i=0;i<=m+n-1;i++){
            getline(cin,str);
            stringstream ss;
            ss<<str;
            ss>>val[i];///工资
            st[i]=0;
            int x;
            while(ss>>x){ //每个人教的课的状态
                x--;
                st[i]|=(1<<x);
            }
        }
        memset(dp,-1,sizeof dp);
        printf("%d\n",dfs(0,(1<<s)-1,0,0));
    }
    return 0;
}
posted @ 2021-09-27 11:15  Evitagen  阅读(47)  评论(0编辑  收藏  举报