uva10817状压dp

    题意:某校有s个课程m个教师和n个求职者,已知每人的工资和能教的课程,要求支付最少的工资使得每门课都至少有两名教师教学。在职教必须雇佣。

    思路:d(i,s0,s1,s2)表示已经雇了i个人且授课状态为(s0,s1,s2),还需要多少钱。其中s0表示没有人授课的课程集合,s1表示只有一个人授课的课程集合,s2表示有2个老师授课的课程集合。(因为不知道要雇佣多少老师,所以状态为当雇佣了i人时还需要多少钱,而不是雇佣了i人花了多少钱)。

 

#include<bits/stdc++.h>
using namespace std;

#define maxn 150
#define maxs 10
#define inf 0x3f3f3f3f
int m,n,s;
int c[maxn],st[maxn];
int d[maxn][1<<maxs][1<<maxs];

int dp(int i,int s0,int s1,int s2)
{
    if(i==m+n)return s2==((1<<s)-1)?0:inf;
    int&ans=d[i][s1][s2];
    if(ans>=0)return ans;//如果ans被赋过值就不用再复制了,因为它代表d[][][],而d[][][]也代表一个dp函数的调用,参数相同,调用函数也相同。
    ans=inf;
    if(i>=m)ans=dp(i+1,s0,s1,s2);
    int m0=st[i]&s0;
    int m1=st[i]&s1;
    s0^=m0;
    s1=(s1^m1)|m0;
    s2|=m1;
    ans=min(ans,dp(i+1,s0,s1,s2)+c[i]);
    return ans;
}

int main()
{
    while(~scanf("%d%d%d",&s,&m,&n)&&m&&n&&s)
    {
        getchar();
        memset(d,-1,sizeof(d));
        memset(st,0,sizeof(st));
        for(int i=0;i<m+n;i++)
        {
            string str;
            getline(cin,str);
            stringstream ss(str);
            int x,flag=1;
            while(ss>>x)
            {
                if(flag){flag=0;c[i]=x;continue;}
                x--;
                st[i]|=(1<<x);
            }
        }
        dp(0,(1<<s)-1,0,0);
        printf("%d\n",d[0][0][0]);
    }
    return 0;
}

 

 


posted @ 2016-07-21 18:11  哲贤  阅读(163)  评论(0编辑  收藏  举报