HDU 6006 状压dp

Engineer Assignment

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 849    Accepted Submission(s): 301

Problem Description

In Google, there are many experts of different areas. For example, MapReduce experts, Bigtable experts, SQL experts, etc. Directors need to properly assign experts to various projects in order to make the projects going smoothly.
There are N projects owned by a director. For the ith project, it needs Ci different areas of experts, ai,0,ai,1,⋅⋅⋅,ai,Ci−1 respective. There are M engineers reporting to the director. For the ith engineer, he is an expert of Di different areas, bi,0,bi,1,...,bi,Di−1.
Each engineer can only be assigned to one project and the director can assign several engineers to a project. A project can only be finished successfully if the engineers expert areas covers the project areas, which means, for each necessary area of the project, there is at least one engineer
masters it.
The director wants to know how many projects can be successfully finished.

Input

The first line of the input gives the number of test cases, T. T test cases follow. Each test case starts with a line consisting of 2 integers, N the number of projects and M the number of engineers. Then N lines follow. The ith line containing the information of the ith project starts
with an integer Ci then Ci integers follow, ai,0,ai,1,...,ai,Ci−1 representing the expert areas needed for the ith project. Then another M lines follow. The ith line containing the information of the ith engineer starts with an integer Di then Di integers follow, bi,0,bi,1,...,bi,Di−1 representing the expert areas mastered by ithengineer.

Output

For each test case, output one line containing “Case #x: y”, where x is the test case number (starting from 1) and y is the maximum number of projects can be successfully finished.

limits

?1≤T≤100.
?1≤N,M≤10.
?1≤Ci≤3.
?1≤Di≤2.
?1≤ai,j,bi,j≤100.

Sample Input

1

3 4

3 40 77 64

3 10 40 20

3 40 20 77

2 40 77

2 77 64

2 40 10

2 20 77

Sample Output

Case #1: 2

Hint

For the first test case, there are 3 projects and 4 engineers. One of the optimal solution is to assign the first(40 77) and second engineer(77 64) to project 1, which could cover the necessary areas 40, 77, 64. Assign the third(40 10) and forth(20 77) engineer to project 2, which could cover the necessary areas 10, 40, 20. There are other solutions, but none of them can finish all 3 projects.
So the answer is 2.

Source

2016 CCPC-Final

题意:

有n个项目,每个项目涉及到最多3个不同的领域,有m个工程师每个工程师掌握最多两个不同的领域,每个工程师只能参与一个项目,问最多能完成几个项目。(数据范围)

代码:

//把工程师状压然后枚举处理到第i个项目所用的状态j,然后如果做第i个项目那么再枚举k状态来完成i项目,j^k状态处理前i-1的项目,这样再加上
//100组样例就超时了,可以预处理出来每一个项目可以用那些状态来完成,所以第三层循环最多45个。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int t,n,m,f[12][1100],a[12][2],b[12][3],sol[12][1100];
bool vis[110],has[1100][1100];
void get_has()
{
    for(int i=0;i<(1<<10);i++){
        for(int j=0;j<(1<<10);j++){
            has[i][j]=1;
            for(int k=0;k<10;k++){
                if(!(i&(1<<k))&&(j&(1<<k))) has[i][j]=0;
            }
        }
    }
}
bool check(int sta,int x)
{
    memset(vis,0,sizeof(vis));
    vis[0]=1;
    for(int i=0;i<m;i++){
        if(sta&(1<<i)){
            vis[a[i][0]]=vis[a[i][1]]=1;
        }
    }
    if(vis[b[x][0]]&&vis[b[x][1]]&&vis[b[x][2]]) return 1;
    return 0;
}
void get_sol()
{
    for(int i=1;i<=n;i++){
        sol[i][0]=0;
        for(int j=0;j<(1<<m);j++){
            if(check(j,i)){
                sol[i][0]++;
                sol[i][sol[i][0]]=j;
            }
        }
    }
}
int main()
{
    get_has();
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        memset(a,0,sizeof(a));
        memset(b,0,sizeof(b));
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++){
            int x;
            scanf("%d",&x);
            for(int j=0;j<x;j++) scanf("%d",&b[i][j]);
        }
        for(int i=0;i<m;i++){
             int x;
             scanf("%d",&x);
             for(int j=0;j<x;j++) scanf("%d",&a[i][j]);
        }
        get_sol();
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++){
            for(int j=1;j<(1<<m);j++){
                f[i][j]=max(f[i][j],f[i-1][j]);
                for(int k=1;k<=sol[i][0];k++){
                    if(!has[j][sol[i][k]]) continue;
                    f[i][j]=max(f[i][j],f[i-1][j^sol[i][k]]+1);
                }
            }
        }
        printf("Case #%d: %d\n",cas,f[n][(1<<m)-1]);
    }
    return 0;
}
时间: 2024-07-30 16:14:16

HDU 6006 状压dp的相关文章

HDU 4284 状压dp+spfa堆优化

题意: 给定n个点 m条无向边 d元. 下面m行表示每条边 u<=>v 以及花费 w 下面top 下面top行 num c d 表示点标为num的城市 工资为c 健康证价格为d 目标是经过给定的top个城市,当到达该城市时,必须马上购买该城市的健康证并打工赚钱(每个城市只打工1次) 问从1城市出发,最后回到1城市,能否收集到所有的健康证 思路: 由于top很小,所以状压dp dp[i][tmp]表示当前处于i点 经过城市的状态为tmp时 身上最多的钱. 首先对dis数组floyd 跑出最短路,

hdu 4906 状压dp

/* ID: neverchanje PROG: LANG: C++11 */ #include<vector> #include<iostream> #include<cstring> #include<string> #include<algorithm> #include<cmath> #include<cstdio> #include<set> #include<queue> #includ

HDU 4892 状压dp

[BestCoder Round #5]冠军的奖励是小米3手机一部 恭喜福州大学杨楠获得[BestCoder Round #4]冠军(iPad Mini一部) <BestCoder用户手册>下载 Defence of the Trees Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 224    Accepted Submiss

HDU 3001 状压DP

有道状压题用了搜索被队友骂还能不能好好训练了,, hdu 3001 经典的状压dp 大概题意..有n个城市 m个道路  成了一个有向图.n<=10: 然后这个人想去旅行.有个超人开始可以把他扔到任意的一个城市..然后他就在城市之间游荡.要满足他要游玩所有的城市..并且.每个城市最多去两次.要求路程最短..如果他不能游完所有的城市,,那么..就输出-1  否则 输出最短距离 如果用搜索...不靠谱  然后用搜索,, 怎么压缩?? 用一个整型数 i 表示他现在的状态..显然一个城市是要用两位..00

Travel(HDU 4284状压dp)

题意:给n个城市m条路的网图,pp在城市1有一定的钱,想游览这n个城市(包括1),到达一个城市要一定的花费,可以在城市工作赚钱,但前提有工作证(得到有一定的花费),没工作证不能在该城市工作,但可以走,一个城市只能工作一次,问pp是否能游览n个城市回到城市1. 分析:这个题想到杀怪(Survival(ZOJ 2297状压dp) 那个题,也是钱如果小于0就挂了,最后求剩余的最大钱数,先求出最短路和 Hie with the Pie(POJ 3311状压dp) 送披萨那个题相似. #include <

hdu 1185 状压dp 好题 (当前状态与上两行有关系)

/* 状压dp 刚开始&写成&&看了好长时间T0T. 状态转移方程 dp[i][k][j]=Max(dp[i][k][j],dp[i-1][l][k]+num[i][j]);(第i行的第j个状态有上一行的第k个状态得到) num[i][j]有两个功能,第一:判断第i行第j个状态是否合法 第二:判断第i行第j个状态的数目 */ #include<stdio.h> #include<string.h> #define N 110 int dp[N][N][N];

HDU 5823 (状压dp)

Problem color II 题目大意 定义一个无向图的价值为给每个节点染色使得每条边连接的两个节点颜色不同的最少颜色数. 对于给定的一张由n个点组成的无向图,求该图的2^n-1张非空子图的价值. n <= 18 解题分析 官方题解: 直接状压dp就行了,f[S]表示点集S的色数,枚举子集转移(子集是独立集).这样是3^n的. 一个复杂度更优的做法是把所有独立集都预处理出来,然后作n次or卷积.这样是n^2*2^n的. 枚举子集的子集的时间复杂度是3^n 啊 . 即 sigma( C(n,k

hdu 3254 (状压DP) Corn Fields

poj 3254 n乘m的矩阵,1表示这块区域可以放牛,0,表示不能,而且不能在相邻的(包括上下相邻)两个区域放牛,问有多少种放牛的方法,全部不放也是一种方法. 对于每块可以放牛的区域,有放或者不放两种选择,状压DP,dp[i][j]表示第 i 行以state[j]这种状态的时候和方法取值. 具体的参考http://www.tuicool.com/articles/JVzMVj 写的很详细. 1 #include<cstdio> 2 #include<cstring> 3 #inc

HDU 6321 (状压dp)

题目大意:: 为给你n个点(n<=10,nn<=10,n) 初始时没有边相连 然后有m个操作(m<=30000m<=30000) 每次可以添加一条边或删除一条边 允许有重边 要求每次操作过后输出选这个图中不相交的k条边有多少种不同的方案 (k=1,2,3--n/2) 题目分析: n最大只有10 , 所以很容易就可以想到状压DP , 但是我在打的时候并没有想出继承状态 , 后来看了题解才略有一丝感悟: 首先一个特别容易看出的状态是每加/减一条边后的状态是由前一个状态转移过来的 : 而