uva10817 - Headmaster's Headache(01背包)

题目:uva10817 - Headmaster‘s Headache(01背包)

题目大意:这间学校开设S门棵,给出校长已经有的师资(n),然后再给吃m个应聘者,给出的师资和应聘者都会给出雇佣他们需要的钱还有他们会教的科目。要使得每门课都至少要有两个老师教,然后从应聘者中挑选人,要求雇佣费用最少,注意之前的请的老师也是要算进去的。

解题思路:01背包,每个应聘者要不雇用,要不就不雇佣,然后这个有8门课,用16位表示,第i门课有一个老师教的话,就在2进制的i位上放上1,如果有两个老师,就在i + s上放上1.

例如4门课都只有一个老师教的话:00001111 如果都有两位老师教的话11110000.细节注意。

代码:

#include <cstdio>
#include <cstring>

const int INF = 0x3f3f3f3f;
const int N = 105;
const int M = 8;
const int maxn = 1<<(2 * M);

int s, m, n;

int T[N][M];
int num[N];
int cost[N];
int dp[maxn][N];
int v[M + 1];
int mm, sum;

int Min (const int a, const int b) { return a < b? a: b;}

void init (int st) {

	for (int i = st; i < mm; i++)
		for (int j = 1; j <= n + 1; j++)
			dp[i][j] = INF;
	for (int i = 1; i <= n + 1; i++)
		dp[mm][i] = 0;
}

int DP (int st, int k) {

	int& ans = dp[st][k];

	if (ans != INF)
		return ans;
	if (k <= n) {

		int newst = st;
		for (int j = 0; j < num[k]; j++) {

			if (newst & (1 << (T[k][j] - 1))) {
				newst |= (1 << (T[k][j] - 1 + s));
				newst &= ~(1 << (T[k][j] - 1));
			} else if (!(newst & (1 << (s + T[k][j] - 1))))
				newst |= (1 << (T[k][j] - 1));
		}
		//	printf ("%d %d\n", st , newst);
		ans = Min (ans, Min (DP(newst, k + 1) + cost[k], DP(st, k + 1)));
	}

	if (ans == INF)
		ans = INF + 1;
	return ans;
}

int main () {

	int st;
	int money, t;
	char ch;
	while (scanf ("%d%d%d", &s, &m, &n), s || m || n) {

		st = sum = 0;
		memset (v, 0, sizeof (v));
		for (int i = 1; i <= m; i++) {

			scanf ("%d", &money);
			sum += money;
			while (scanf ("%c", &ch)) {
				if (ch == '\n')
					break;
				if (ch >= '1' && ch <= '8') {

					if (v[ch - '0'] < 2) {
						v[ch - '0']++;
					}
				}
			}
		}

		for (int i = 1; i <= n; i++) {

			scanf ("%d", &cost[i]);
			t = 0;
			while (scanf ("%c", &ch)) {

				if (ch == '\n')
					break;
				if (ch >= '1' && ch <= '8') {

					T[i][t++] = ch - '0';
				}
			}
			num[i] = t;
		}

		for (int i = 1; i <= s; i++)
			if (v[i])
				st += 1 << (i - 1 + (v[i] - 1) * s);

		mm = (1<<(2 * s)) - (1<<s);

		init (st);
		printf ("%d\n", DP(st, 1) + sum);
	}
	return 0;
}

uva10817 - Headmaster's Headache(01背包)

时间: 2024-11-06 13:54:13

uva10817 - Headmaster's Headache(01背包)的相关文章

UVA - 10817 Headmaster&#39;s Headache (状压类背包dp+三进制编码)

题目链接 题目大意:有S门课程,N名在职教师和M名求职者,每名在职教师或求职者都有自己能教的课程集合以及工资,要求花费尽量少的钱选择一些人,使得每门课程都有至少两人教.在职教师必须选. 可以把“每个课程已经分别有几个人教”作为状态来进行转移,每个人能教的课程集合作为“物品重量”,工资作为“价值”来更新dp值,类似01背包,每放进一个人,从后往前更新即可. 状态的表示可以用三进制编码,为了写起来舒服,我写了个结构体作为状态和编码转换的桥梁,也可以进行状态的“加法运算”,虽然速度比较慢就是了~~ 有

Headmaster&#39;s Headache UVa10817【DP】(缺)

题目: The headmaster of Spring Field School is considering employing some new teachers for certain subjects. There are a number of teachers applying for the posts. Each teacher is able to teach one or more subjects. The headmaster wants to select appli

【UVa】Headmaster&#39;s Headache(状压dp)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1758 晕....状压没考虑循环方向然后错了好久.. 这点要注意...(其实就是01背包变成了完全背包QAQ 我们将课程拆成两个点,然后状压 那么答案就是(1<<(s<<1))-1 转移就不说了,,,,,太简单.. #include <cstdio> #in

Headmaster&#39;s Headache

题意: s门课程,现任老师有m个给出工资,和他们能教的课,现在有n个应聘的老师,给出费用和能教的课程标号,求使每门课都至少有两个老师教的最小花费 分析: n个老师选或不选有背包的特征,n很小想到用状压,s1表示每门课至少有一个老师教的情况,s2表示每门课至少有2个老师教的情况 起始状态是现任老师形成,dp[(j|ca[i])][(ca[i]&j)|k]=min(dp[(j|ca[i])][(ca[i]&j)|k],dp[j][k]+cost[i]); ca[i]是i个应聘者能教课程的状态

UVA 10817 Headmaster&#39;s Headache 状压DP

记录两个状态S1,S2分别记录哪些课程被1个人教过或2个人教过,然后记忆化搜索 UVA - 10817 Headmaster's Headache Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem D: Headmaster's Headache Time limit: 2 seconds The headmaster of Spr

状压DP UVA 10817 Headmaster&#39;s Headache

题目传送门 1 /* 2 题意:学校有在任的老师和应聘的老师,选择一些应聘老师,使得每门科目至少两个老师教,问最少花费多少 3 状压DP:一看到数据那么小,肯定是状压了.这个状态不好想,dp[s1][s2]表示s1二进制表示下至少有1位老师的科目集合 4 s2表示至少有2位老师的科目集合所花费的最小金额,状态转移方程(01):dp[t1][t2]=min(dp[t1][t2],dp[j][k]+c[i]); 5 j,k为当前两个集合,t1,t2为转移后的集合,另外求t1,t2用到了& |位运算

UVA 562 Dividing coins --01背包的变形

01背包的变形. 先算出硬币面值的总和,然后此题变成求背包容量为V=sum/2时,能装的最多的硬币,然后将剩余的面值和它相减取一个绝对值就是最小的差值. 代码: #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; #define N 50007 int c[102],d

17-又见01背包

/*                                        又见01背包时间限制:1000 ms  |  内存限制:65535 KB难度:3 描述        有n个重量和价值分别为wi 和 vi 的 物品,从这些物品中选择总重量不超过 W     的物品,求所有挑选方案中物品价值总和的最大值.    1 <= n <=100    1 <= wi <= 10^7    1 <= vi <= 100    1 <= W <= 10^

HDU - 2602 Bone Collector(01背包讲解)

题意:01背包:有N件物品和一个容量为V的背包.每种物品均只有一件.第i件物品的费用是volume[i],价值是value[i],求解将哪些物品装入背包可使价值总和最大. 分析: 1.构造二维数组:dp[i][j]---前i件物品放入一个容量为j的背包可以获得的最大价值. dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - volume[i]] + value[i]);---(a) (1)dp[i - 1][j]---不放第i件物品,因此前i件物品放入一个容量为