UVA10817-Headmaster's Headache(动态规划基础)

Problem UVA10817-Headmaster's Headache

Time Limit: 4500 mSec

Problem Description

Input

The input consists of several test cases. The format of each of them is explained below: The first line contains three positive integers S, M and N. S (≤ 8) is the number of subjects, M( ≤ 20) is the number of serving teachers, and N (≤ 100) is the number of applicants. Each of the following M lines describes a serving teacher. It first gives the cost of employing him/her (10000 ≤ C ≤ 50000), followed by a list of subjects that he/she can teach. The subjects are numbered from 1 to S. You must keep on employing all of them. After that there are N lines, giving the details of the applicants in the same format. Input is terminated by a null case where S = 0. This case should not be processed.

 Output

For each test case, give the minimum cost to employ the teachers under the constraints.
 

 Sample Input

2 2 2
10000 1
20000 2
30000 1 2
40000 1 2
0 0 0
 

Sample Output

60000

题解:状压dp,但是比较麻烦的地方在于不少于2人,因此最直接的想法就是三进制枚举,不过三进制写起来有些麻烦,转念一想,其实可以用两个二进制位来代替这个三进制,我的两个二进制位的状态定义其实有些问题,比较正的思路就是前八位和后八位分别代表一个和大于等于两个。我的代码是跟着lrj的思路做的,实现的思路还是很好的,三进制可以转成两个二进制,用两个集合来表示整个状态,很值得学习(好写嘛),状态定义为dp[i][s1][s2],表示考虑到前i个人,在状态(s1,s2)之下到达目标状态还要花费多少。这样方程就很好写了。在转移状态的时候需要位运算,这个硬想是很困难的,画个图就很简单了,交,并,对称差分别对应&,|,^。

 1 #include <bits/stdc++.h>
 2 
 3 using namespace std;
 4 
 5 const int maxs = 10, maxm = 25, maxn = 105;
 6 const int INF = 1e9;
 7 
 8 int s, m, n;
 9 int cost[maxn + maxm], teach[maxn + maxm];
10 int dp[maxm + maxn][1 << maxs][1 << maxs];
11 
12 int DP(int i, int s0, int s1, int s2) {
13     if (i == m + n) return s2 == (1 << s) - 1 ? 0 : INF;
14     int& ans = dp[i][s1][s2];
15     if (ans >= 0) return ans;
16 
17     ans = INF;
18     if (i >= m) ans = DP(i + 1, s0, s1, s2);
19 
20     int t0 = s0 & teach[i];        //new subjects
21     int t1 = s1 & teach[i];
22     s0 ^= t0; s1 = (s1^t1) | t0; s2 |= t1;
23     ans = min(ans, DP(i + 1, s0, s1, s2) + cost[i]);
24     return ans;
25 }
26 
27 int main()
28 {
29     //freopen("input.txt", "r", stdin);
30     string str;
31     while (getline(cin, str)) {
32         stringstream ss(str);
33         ss >> s >> m >> n;
34         if (s == 0) break;
35         memset(teach, 0, sizeof(teach));
36         memset(dp, -1, sizeof(dp));
37         for (int i = 0; i < n + m; i++) {
38             getline(cin, str);
39             stringstream ss(str);
40             ss >> cost[i];
41             int t;
42             while (ss >> t) {
43                 t--;
44                 teach[i] |= (1 << t);
45             }
46         }
47         printf("%d
", DP(0, (1 << s) - 1, 0, 0));
48     }
49     return 0;
50 }
原文地址:https://www.cnblogs.com/npugen/p/9817555.html