UVa 10817 Headmaster‘s Headache 【01揹包 位運算】

題意:劉汝佳訓練指南p95


題解:此題可以設dp[s2][s1] = 授課狀態爲s2、s1時的最小花費(s1爲課程授課狀態爲1的集合,s2爲授課狀態爲2的集合)

然後視招募的新老師爲要裝進揹包裏的物品,授課狀態s2,s1爲容量,最終答案就爲dp[(1<<S)-1][(1<<S)-1](S爲課程數目)

具體轉移方程如下:

設s2,s1爲招募該老師前的狀態,ns2,ns1爲招募該老師後的狀態則,ns1 = s1 | s ,ns2 = s2 | (s1 & s) ,(s爲該老師能教授的課程)

dp[ns2][ns1] = min(dp[s1 | s[i]][s2 | (s1 & s[i])]) + v[i],s[i]是第i個老師授課集合,v[i]是第i個老師的收費


#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<cmath>
#include<stdlib.h>
#include <string.h>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<time.h>
using namespace std;
#define MAX_N 505
#define inf 0x3f3f3f3f
#define LL long long
#define ull unsigned long long
const LL INF = 1e18;
const int mod = 1e8+7;
typedef pair<double, int>P;

int S, M, N;
int tC[25];
int aC[105];
int teacher[25];
int applicant[105];
int dp[1<<8][1<<8];
int getT()
{
    char c;
    int ans = 0;
    int d;
    c = getchar();
    while(c!='\n') {
        scanf("%d", &d);
        d--;
        ans |= (1<<d);
        c = getchar();
    }
    return ans;
}
void init()
{
    memset(dp, inf, sizeof(dp));
}
int main()
{
    while(cin >> S >> M >> N && S+M+N) {
        init();
        int s1 = 0;
        int s2 = 0;
        int sum = 0;
        for(int i=0; i<M; i++) {
            scanf("%d", &tC[i]);
            teacher[i] = getT();
            sum += tC[i];
            s2 |= (s1 & teacher[i]);
            s1 |= teacher[i];
        }
        for(int i=0; i<N; i++) {
            scanf("%d", &aC[i]);
            applicant[i] = getT();
        }
        dp[s2][s1] = sum;
        for(int k=0; k<N; k++) {
            int s = applicant[k];
            for(int i=(1<<S)-1; i>=0; i--) {
                for(int j=(1<<S)-1; j>=0; j--) {
                    int ns1 = j|s;
                    int ns2 = i|(j&s);
                    dp[ns2][ns1] = min(dp[ns2][ns1], dp[i][j]+aC[k]);
                }
            }
        }
        /*
       for(int i=0; i<(1<<S); i++) {
            for(int j=0; j<(1<<S); j++) {
                if(dp[i][j] == inf)
                    printf("0 ");
                else
                    printf("%d ",dp[i][j]);
            }
            puts("");
        }*/
        cout << dp[(1<<S)-1][(1<<S)-1] << endl;
    }
    return 0;
}
/*
8 4 3
1000 1
1000 2
1000 3
1000 2
50000 1 5 7 3 4
50000 1 6 8
50000 1 2 3 4 5 6 7 8
*/


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章