• hdu6006 Engineer Assignment 状态dp 定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。


    /**
    题目:hdu6006 Engineer Assignment
    链接:http://acm.hdu.edu.cn/showproblem.php?pid=6006
    题意:已知n个工程,每个需要某些领域的专家。有m个工程师,每个人擅长一些领域。  m<=10
    一个工程师只能参加一个工程。一个工程可以多个工程师参加。
    如果参加某个工程的工程师他们擅长的领域覆盖了该工程需要的领域。那么该工程可以执行。
    问最多可以执行多少个工程。
    思路:
    定义dp[i][s]表示前i个工程状态为s可以执行的最大工程数。s表示前i个工人选走了s状态的工程师。
    dp[i][s] = max(dp[i][s],dp[i-1][s']+1);  s'为s的子集,且f[i][s-s'] = 1; 表示i这个工程,分配s-s'的工程师,可以完成。
    
    
    
    */
    
    
    
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<map>
    #include<vector>
    #include<cstring>
    using namespace std;
    typedef long long LL;
    const int N = 2e5+100;
    const int inf = 0x3f3f3f3f;
    vector<int> pro[12], eng[12];
    map<int,int> mp;
    int f[11][1<<10];
    int mv[12];
    int rm[1<<20];
    int n, m;
    int dp[2][1<<10];
    void init()
    {
        mv[0] = 0;
        for(int i = 1; i <= m; i++){
            int s = 0;
            for(int j = 0; j < eng[i].size(); j++){
                s |= 1<<(mp[eng[i][j]]-1);
            }
            mv[i] = s;
        }
        int len = (1<<m);
        rm[0] = 0;
        for(int i = 1; i < len; i++){
            rm[i] = 0;
            for(int j = 1; j <= m; j++){
                if(i&(1<<(j-1))){
                    rm[i] |= mv[j];
                }
            }
        }
    
        memset(f, 0, sizeof f);
        for(int i = 1; i <= n; i++){
            int s1 = 0;
            for(int j = 0; j < pro[i].size(); j++){
                if(mp[pro[i][j]]==0){
                    s1 = 0; break;
                }
                s1 |= 1<<(mp[pro[i][j]]-1);
            }
            if(s1==0) continue;
            for(int j = 1; j < len; j++){
                if((rm[j]&s1)==s1){
                    f[i][j] = 1;
                }
            }
        }
    }
    int main()
    {
        int cas = 1, T;
        cin>>T;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            int num, x;
            for(int i = 1; i <= n; i++){
                scanf("%d",&num);
                pro[i].clear();
                for(int j = 1; j <= num; j++){
                    scanf("%d",&x);
                    pro[i].push_back(x);
                }
            }
    
            mp.clear();
            int cnt = 1;
            for(int i = 1; i <= m; i++){
                scanf("%d",&num);
                eng[i].clear();
                for(int j = 1; j <= num; j++){
                    scanf("%d",&x);
                    eng[i].push_back(x);
                    if(mp[x]==0){
                        mp[x] = cnt++;
                    }
                }
            }
            int len = (1<<m);
            init();
            int now = 0;
            for(int i= 0; i < len; i++) dp[0][i] = 0;
            for(int i = 1; i <= n; i++){
                now ^= 1;
                for(int s = 0; s < len; s++){
                    dp[now][s] = dp[now^1][s];///根据定义,所以传递。
                    if(f[i][s]==0) continue;
                    for(int s0 = s; s0; s0 = (s0-1)&s){
                        if(f[i][s0])
                            dp[now][s] = max(dp[now][s],dp[now^1][s-s0]+1);
                    }
                }
            }
            printf("Case #%d: %d
    ",cas++,dp[now][len-1]);
        }
        return 0;
    }
  • 相关阅读:
    弹窗
    ajax
    Jquery元素选取、常用方法
    PDO
    session的使用
    投票练习题
    php 批量删除
    php 连接数据库的增删改查
    面向对象的加载类和设计模式
    面向对象三大特性
  • 原文地址:https://www.cnblogs.com/xiaochaoqun/p/7241362.html
Copyright © 2020-2023  润新知