UVa P10817 校长的烦恼【背包DP】【状态压缩】

f[S1][S2] f [ S 1 ] [ S 2 ] 表示达到 S1 S 1 S2 S 2 状态的最少花费,

其中:
S1 S 1 的二进制位表示某一门课程是否已经有一个老师教,
S2 S 2 的二进制位表示某一门课程是否已经有两个老师教。

设当前老师能教的课程用二进制表示为 P P

那么:
第一门课程现在的状态就更新为: A=S1|P A = S 1 | P
第二门课程现在的状态就更新为: B=(S1&P)|S2 B = ( S 1 & P ) | S 2

所以得到状态转移方程:

f[A][B]=min{f[S1][S2]+Cost} f [ A ] [ B ] = m i n { f [ S 1 ] [ S 2 ] + C o s t }

发现就是一个背包,所以随便写一写就好:

int main(){
    LL I,J,K,L;
    scanf("%lld%lld%lld",&S,&M,&N);
    for(I=1;I<=M+N;I++){
        scanf("%d",&Cost[I]);
        while(true){
            char CH=getchar();
            if(CH=='\n'){
                break;
            } else if(isdigit(CH)){
                J=CH-'1';
                P[I]|=(1<if(I<=M){
                    Cnt[J]++;
                }
            }
        }
        if(I<=M){
            Sum+=Cost[I];
            S1|=P[I];
        }
    }K=(1<1;
    for(I=0;I<=S-1;I++){
        if(Cnt[I]>=2){
            S2|=(1<for(I=0;I<=K;I++){
        for(J=0;J<=K;J++){
            DP(I,J)=Inf;
        }
    }DP(S1,S2)=Sum;
    for(L=M+1;L<=M+N;L++){
        for(I=K;I>=0;I--){
            for(J=K;J>=0;J--){
                LL X=(I&P[L])|J,Y=I|P[L];
                DP(Y,X)=min(DP(Y,X),DP(I,J)+Cost[L]);
            }
        }
    }
    printf("%lld",DP(K,K));
    return 0;
}

你可能感兴趣的:(UVa,动态规划与递推,动态规划-背包DP,动态规划-状态压缩)