zoukankan      html  css  js  c++  java
  • UVA10817 校长的烦恼 Headmaster’s Headache(记忆化搜索+状压dp)

    题意:

    题目描述 斯普林菲尔德(春之田野???)学院的校长正在考虑为某些科目招聘新老师 现在有一批申请岗位的老师 每个老师能教一个或多个科目 校长想要选择一些申请者以保证每个科目都至少有两名老师能教 同时总共花的钱要最小

    输入格式: 输入由多组测试组成,它们的格式如下: 第一行包含三个给定的整数S,M和N, S (<=8)是科目的总数 M(<=20)是在职教师数,N(<=100)是应聘者的数量

    接下来M行每行描述一个在职教师 首先给出雇佣他的花费C (10000<=C<=50000) ,接下来是他能教的科目列表 科目用1—S的整数表示 你必须保证继续聘用他们

    之后N行,以同样格式给出应聘者的信息

    输入以一个空测试S=0结束,你不应当处理它 (这句有些别扭,不过懂意思就好)

    思路:

     科目的总数只有$8$,考虑把每个老师会哪几门课这个条件转化为二进制数表示。

    然后记忆化搜索:$dp[i][s0][s1][s2]$表示枚举到第$i$个人时,没有人教的课程的二进制数表示为$s0$,有一个人教的课程表示为$s1$,有两个人教的课程表示为$s2$.

    当枚举到第$i$个人并且$i>=m$时(所有的下标从$0$开始),可以不选择这个人。

    对于所有的教师都可以选择这个人,考虑这个人被选后会对记忆化搜索的变量产生哪些影响。

    1.记录别人都不会但是第$i$个人会的课程

    2.记录别人有一个人会而且第$i$个人也会的课程。

    3.

    s0=s0^m0;///在没人会的集合里面去除i会的
    s1=(s1^m1)|m0;///首先在一个人会的集合里去除i也会的,然后加上只有i会的,这是所有一个人会的
    s2=s2|m1;///现在相当于两个人会

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef unsigned long long ull;
    typedef pair<ll, ll>PLL;
    typedef pair<int, int>PII;
    typedef pair<double, double>PDD;
    #define I_int ll
    inline ll read()
    {
        ll x = 0, f = 1;
        char ch = getchar();
        while(ch < '0' || ch > '9')
        {
            if(ch == '-')f = -1;
            ch = getchar();
        }
        while(ch >= '0' && ch <= '9')
        {
            x = x * 10 + ch - '0';
            ch = getchar();
        }
        return x * f;
    }
    #define read read()
    #define closeSync ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
    #define multiCase int T;cin>>T;for(int t=1;t<=T;t++)
    #define rep(i,a,b) for(int i=(a);i<=(b);i++)
    #define repp(i,a,b) for(int i=(a);i<(b);i++)
    #define per(i,a,b) for(int i=(a);i>=(b);i--)
    #define perr(i,a,b) for(int i=(a);i>(b);i--)
    ll ksm(ll a, ll b, ll p)
    {
        ll res = 1;
        while(b)
        {
            if(b & 1)res = res * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return res;
    }
    const int inf = 0x3f3f3f3f;
    #define PI acos(-1)
    const int maxn=1000000000;
    
    int s,n,m,val[150],st[150];
    int dp[150][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;///首先在一个人会的集合里去除i也会的,然后加上只有i会的,这是所有一个人会的
        s2=s2|m1;///现在相当于两个人会
        res=min(res,dfs(i+1,s0,s1,s2)+val[i]);
        return res;
    }
    
    int main()
    {
    
        string str;
        while(getline(cin,str)){
            stringstream ss;
            ss<<str;
            ss>>s>>m>>n;
            if(!s) break;
    
            rep(i,0,m+n-1){
                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
    ",dfs(0,(1<<s)-1,0,0));
        }
    
        return 0;
    }
    
    /*
    
    **/
    View Code
  • 相关阅读:
    移动方法
    linux主编号的动态分配
    linux 分配和释放设备编号
    linux设备编号的内部表示
    linux主次编号
    linux模块参数
    linux scull 的设计
    linux模块加载竞争
    linux清理函数
    linux初始化中的错误处理
  • 原文地址:https://www.cnblogs.com/OvOq/p/14859056.html
Copyright © 2011-2022 走看看