Uva10817

题目链接

s0表示哪些科目没有一个老师教,s1表示是哪些科目只有一个老师教,s2表示有哪些科目有两个老师教,d(i,s1,s2)表示考虑钱i个时的最小花费,状态转移方程d(i,s1,s2)=min{d(i+1,s1′,s2′)+c[i],d(i+1,s1,s2)} 【c[i]表示聘用这个老师的花费,s1′和s2′表示招聘这个老师后更新的新状态′

第一项表示聘用,第二项不聘用,只有i>m才出现第二项,因为在职教师不能够辞退。

#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;

const int maxn = 130;
const int INF = 1 << 20;
int s, m, n, x;
int d[maxn][1 << 8][1 << 8];
int c[maxn], st[maxn];

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;//在没有老师教的科目中求职者能教的课程
    int 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()
{
    string str;
    while (getline(cin, str))
    {
        memset(st, 0, sizeof(st));
        stringstream ss(str);
        ss >> s >> m >> n;
        if (s == 0)
            break;
        for (int i = 0; i < m + n; i++)
        {
            getline(cin, str);
            stringstream ss(str);
            ss >> c[i];
            while (ss >> x)
            {
                st[i] |= 1 << (x - 1);//老师所能教的科目
            }
        }
        memset(d, -1, sizeof(d));
        cout << dp(0, (1 << s) - 1, 0, 0) << endl;//(1 << s) - 1表示一开始所有的课程都没有老师教
    }
}

你可能感兴趣的:(UVa,动态规划,状压DP)