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;
    }
    
  • 相关阅读:
    交叉验证概述
    【Python那些事儿之十】range()和xrange()
    Numpy基础笔记
    matplotlib中使用imshow绘制二维图
    Django+Django-Celery+Celery的整合实战
    Nginx+uWSGI+Django部署web服务器
    uwsgi
    uwsgi 神器问题
    disagrees about version
    协议基础:SMTP:使用Telnet学习SMTP协议
  • 原文地址:https://www.cnblogs.com/MyNameIsPc/p/8879615.html
Copyright © 2011-2022 走看看