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; }

你可能感兴趣的:(master)