题意:
有一个学校想要聘请老师,要求每个学科都有两个以上的老师授课,并且要使总费用最小。有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;
}