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


  • 相关阅读:
    CCNode作为容器实现显示区域剪裁
    使用CCNode作为容器容易踩的坑
    走了很多弯路的CCScrollView
    常用es6特性归纳-(一般用这些就够了)
    WebP图片优化
    es6 Promise 异步函数调用
    网站性能优化
    dom元素分屏加载
    js顺序加载与并行加载
    移动端真机调试
  • 原文地址:https://www.cnblogs.com/wiklvrain/p/8179367.html
Copyright © 2020-2023  润新知