UVa 10817 Headmaster's Headache(状态压缩DP)

题意:

有一个学校想要聘请老师,要求每个学科都有两个以上的老师授课,并且要使总费用最小。有S(最多8个)个学科,现任的M(最多20个)个老师(你必须继续聘请他们),N(最多100个)份申请。后来的M行每行有至少两个整数,表示现任的老师的工资,和他所教授的课程(可能不止一个)。再后来的N行每行有也有至少两个整数表示聘请这个老师所需的费用,以及他所教授的课程(可能不止一个)。

思路:

http://www.cnblogs.com/staginner/archive/2011/12/07/2278727.html

如何进行状态压缩很关键,链接中的思路有待于细细琢磨。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <climits>
#include <cctype>
#include <algorithm>
using namespace std;

const int MAXD = 10000;
const int MAXN = 110;
int s, m, n;
int dp[MAXN][MAXD];
int need[12], tech[MAXN][12], state[12];
int cost[MAXN];

void solve()
{
    for (int i = 1; i <= s; ++i)
        need[i] = 2;

    char b[100];
    int v = 0;
    for (int i = 0; i < m; ++i)
    {
        gets(b);
        int k = strlen(b);
        int t;
        sscanf(b, "%d", &t);
        v += t;

        int j = 0;
        while (isdigit(b[j]))
            ++j;

        for (++j; j < k; ++j)
        {
            sscanf(&b[j], "%d", &t);
            if (need[t])
                --need[t];

            while (isdigit(b[j]))
                ++j;
        }
    }

    memset(tech, 0, sizeof(tech));
    for (int i = 1; i <= n; ++i)
    {
        gets(b);
        int k = strlen(b);
        int t;
        sscanf(b, "%d", &t);
        cost[i] = t;

        int j = 0;
        while (isdigit(b[j]))
            ++j;

        for (++j; j < k; ++j)
        {
            sscanf(&b[j], "%d", &t);
            tech[i][t] = 1;

            while (isdigit(b[j]))
                ++j;
        }
    }

    memset(dp, 0x3f, sizeof(dp));
    int P = 0;
    for (int i = 1; i <= s; ++i)
        P = 3 * P + 2;

    for (int i = 0; i <= P; ++i)
    {
        int t = i;
        for (int j = 1; j <= s; ++j)
            state[j] = t % 3, t /= 3;
        int j;
        for (j = 1; j <= s && state[j] >= need[j]; ++j);
        if (j == s + 1)
            dp[0][i] = v;
    }

    for (int i = 1; i <= n; ++i)
    {
        for (int j = 0; j <= P; ++j)
        {
            int t = j;
            for (int k = 1; k <= s; ++k)
                state[k] = t % 3, t /= 3;

            for (int k = 1; k <= s; ++k)
                if (tech[i][k] && state[k] < 2)
                    ++state[k];

            t = 0;
            for (int k = s; k >= 1; --k)
                t = 3 * t + state[k];

            dp[i][j] = min(dp[i-1][j], dp[i-1][t] + cost[i]);
        }
    }
}

int main()
{
    char b[100];
    while (gets(b))
    {
        sscanf(b, "%d %d %d", &s, &m, &n);
        if (!s)
            break;
        
        solve();
        printf("%d\n", dp[n][0]);
    }

    return 0;
}
posted @ 2012-11-26 11:38  kedebug  阅读(593)  评论(0编辑  收藏  举报