zoukankan      html  css  js  c++  java
  • UVA-10817 Headmaster's Headache

    题目大意:

    有s个学科,现在在学校有n个教师在教书,这些教师必须要被雇佣,现在还有m个教师正在应聘。现在给出这n个在职教师的工资和能教的科目,给出m个应聘教师的工资和能教的科目,现在希望这s个科目,每个都有至少两个教师教授,问你最少需要支付的工资是多少。

    解题思路:

    动态规划。状压DP。

    dp[i]表示i这个状态需要支付的最少工资。因为每个科目至少两个教师,且最多只有8个科目,所以很明显状压DP。

    设状态st,st有2*s有效位,低s位表示s个科目有一个教师,高s位也表示s个科目有一个教师。当2*s位都为1的时候表示最少能满足要求的状态。

    设状态tt,表示第i个教师能教授科目的状态。

    那么状态转移就可以写为:

    dp[st | tt] = dp[st] + c[i]

    代码:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 105;
    const int INF = 0x3f3f3f3f;
    const int maxm = (1 << 16) + 10;
    
    int s, m, n;
    int tot, vis[10], tt[257];
    int a[10], c[maxn], dp[maxm], ss[maxn][10];
    
    bool judge(int a, int b) {
    	while (b) {
    		if ((b & 1) && !(a & 1)) return false;
    		b >>= 1; a >>= 1;
    	}
    	return true;
    }
    void dfs(int p, int st, int j) {
    	if (p == ss[j][0]) {
    		tt[tot++] = st | (1 << (ss[j][p] - 1));
    		tt[tot++] = st | (1 << (ss[j][p] - 1 + s));
    		return;
    	}
    
    	dfs(p + 1, st | (1 << (ss[j][p] - 1)), j);
    	dfs(p + 1, st | (1 << (ss[j][p] - 1 + s)), j);
    }
    int main() {
    	while (~scanf("%d%d%d", &s, &m, &n) && s) {
    		memset(a, 0, sizeof(a));
    		int tmp, ans = 0; char op;
    		for (int i = 0; i < m; ++i) {
    			scanf("%d", &tmp); ans += tmp;
    			while (scanf("%d%c", &tmp, &op) == 2) {
    				++a[tmp - 1];
    				if (op == '
    ') break;
    			}
    		}
    		for (int i = 1; i <= n; ++i) {
    			scanf("%d", &c[i]); int tmp, cnt = 0;
    			memset(vis, 0, sizeof(vis));
    			while (scanf("%d%c", &tmp, &op) == 2) {
    				if (!vis[tmp]) { ss[i][++cnt] = tmp; vis[tmp] = 1; }
    				if (op == '
    ') break;
    			}
    			ss[i][0] = cnt;
    		}
    
    		int be = 0, st = (1 << (2 * s)) - 1;
    		for (int i = 0; i < s; ++i) {
    			if (!a[i]) continue;
    			else if (a[i] == 1) be += (1 << (i + s));
    			else if (a[i] >= 2) be += (1 << i) + (1 << (s + i));
    		}
    
    		memset(dp, 0x3f, sizeof(dp));
    		dp[be] = 0;
    		for (int j = 1; j <= n; ++j) {
    			tot = 0;
    			dfs(1, 0, j);
    			
    			for (int i = st; i >= be; --i) {
    				if (!judge(i, be)) continue;
    				for (int k = 0; k < tot; ++k) {
    					if (i == (i | tt[k])) continue;
    					dp[i | tt[k]] = min(dp[i | tt[k]], dp[i] + c[j]);
    				}
    			}
    		}
    		printf("%d
    ", ans + dp[st]);
    	}
    	return 0;
    }


  • 相关阅读:
    飞入飞出效果
    【JSOI 2008】星球大战 Starwar
    POJ 1094 Sorting It All Out
    POJ 2728 Desert King
    【ZJOI 2008】树的统计 Count
    【SCOI 2009】生日快乐
    POJ 3580 SuperMemo
    POJ 1639 Picnic Planning
    POJ 2976 Dropping Tests
    SPOJ QTREE
  • 原文地址:https://www.cnblogs.com/wiklvrain/p/8179367.html
Copyright © 2011-2022 走看看