hdu 6006 Engineer Assignment

来源:互联网 发布:淘宝旺铺下载 编辑:程序博客网 时间:2024/06/06 01:46

题目链接:

http://acm.split.hdu.edu.cn/showproblem.php?pid=6006

题解:

状态压缩+类背包dp

代码:

#include <cmath>#include <vector>#include <queue>#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>using namespace std;#define met(a,b) memset(a,b,sizeof(a))#define inf 0x3f3f3f3ftypedef long long ll;const int maxn = 10+10;vector<int>a[maxn],b[maxn];//int a[maxn][maxn],b[maxn][maxn];vector<int> num[2000];int p[150];int main(){    int t;    scanf("%d",&t);    int id=1;    while(t--)    {        int n,m;        scanf("%d%d",&n,&m);        met(p,0);        for(int i=0;i<20;i++)            a[i].clear();        for(int i=0;i<20;i++)            b[i].clear();        for(int i=0;i<=2000;i++)            num[i].clear();//            项目的数量        for(int i=1;i<=n;i++)        {            int cnt;            scanf("%d",&cnt);            while(cnt--)            {                int num;                scanf("%d",&num);                a[i].push_back(num);            }        }//        工程师的数量        for(int i=0;i<m;i++)        {            int cnt;            scanf("%d",&cnt);            while(cnt--)            {                int num;                scanf("%d",&num);                b[i].push_back(num);            }        }        for(int i=1;i<=n;i++)        {            for(int s=0;s<(1<<m);s++)//                枚举所有会组成的情况            {                int cnt=0;                met(p,0);                for(int k=0;k<m;k++)//                    查看当前的工程师是不是在这个情况里面                {                    if(s&(1<<k))                    {                        cnt++;                        for(int j=0;j<b[k].size();j++)                            p[b[k][j]]=1;                    }                }                if(cnt>3)                    continue;                bool flag=false;                for(int j=0;j<a[i].size();j++)//                    查看当前的项目是不是可以满足                {                    if(p[a[i][j]]==0)                        flag=true;                }                if(!flag)                    num[i].push_back(s);            }        }        int dp[maxn][1<<11];        met(dp,0);        for(int i=1;i<=n;i++)        {            for(int s=0;s<(1<<m);s++)            {//                暴力枚举当前所有的情况                for(int j=0;j<num[i].size();j++)                {                    if((s|num[i][j])==s)//                        通过上面的筛选中,找到合适的满足情况的组合                    {                        dp[i][s]=max(dp[i-1][s-num[i][j]]+1,dp[i][s]);//                        类似于背包的更新                    }                }                dp[i][s]=max(dp[i-1][s],dp[i][s]);            }        }        printf("Case #%d: ",id++);        printf("%d\n",dp[n][(1<<m)-1]);    }}//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
原创粉丝点击