zoukankan      html  css  js  c++  java
  • uva 10817(数位dp)

    uva 10817(数位dp)

    某校有m个教师和n个求职者,需讲授s个课程(1<=s<=8, 1<=m<=20, 1<=n<=100)。已知每人的工资c(10000<=c<=50000)和能教的课程集合,要求支付最少的工资使得每门课都至少有两名教师能教。在职教师不能辞退。

    用两个集合,s1表示恰好有一个人教的科目集合,s2表示至少有两个人教的科目集合。设计状态(d(i, s1, s2))表示考虑了后n-i个人时的最小花费。把所有人从1到n+m编号,那么m~n+m-1表示应聘者。因此,状态转移方程为(d(i, s1, s2)=min{d(i+1, s1', s2')+c[i], d(i+1, s1, s2)}),其中第二项只能在应聘者中使用。s1‘和s2’分别表示招聘第i个人之后s1和s2的新值。具体计算方式见代码。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxs=8, maxn=125, INF=1e9;
    int s, m, n, t, c[maxn], st[maxn];
    int f[maxn][1<<maxs][1<<maxs];  //[0, 1<<n)正好表示n个元素的所有子集
    //c:每个人的工资 st:每个人教授的科目集合
    char ch;
    
    int d(int cur, int s0, int s1, int s2){  //si:有i个人教授的科目集合
        if (cur==n) return (s2+1==(1<<s)?0:INF);
        int &ans=f[cur][s1][s2];
        if (ans>=0) return ans; ans=INF;  //必须要>=0!
        if (cur>=m) ans=min(ans, d(cur+1, s0, s1, s2));  //不买这个人
        s2^=s1&st[cur]; s1^=s1&st[cur];
        s1^=s0&st[cur]; s0^=s0&st[cur]; //如果选了这个人
        ans=min(ans, d(cur+1, s0, s1, s2)+c[cur]);
        return ans;
    }
    
    int main(){
        while (~scanf("%d%d%d", &s, &m, &n)&&s){
            n=n+m; memset(f, -1, sizeof(f));
            memset(st, 0, sizeof(st));
            for (int i=0; i<n; ++i){
                scanf("%d%c", &c[i], &ch);
                while (ch!='
    '){
                    scanf("%d%c", &t, &ch);
                    st[i]|=(1<<(t-1));
                }
            }
            printf("%d
    ", d(0, (1<<s)-1, 0, 0));
        }
        return 0;
    }
    
  • 相关阅读:
    前端学习的几个网站
    程序员怎么写出一份漂亮的简历
    程序员斗图专用表情包
    2018年国内就业薪资高的7大编程语言排行
    微信小程序初步运营方案
    「干货」从菜鸟到大神,前端学习书籍推荐
    数据分析概述和理论基础
    十大厂商为什么要联合推出“快应用”对标小程序?
    数据分析的过程
    H5混合开发二维码扫描以及调用本地摄像头
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/8879615.html
Copyright © 2011-2022 走看看