您的位置:首页 > 其它

UVa 10817 Headmaster‘s Headache 【01背包 位运算】

2017-03-07 21:28 483 查看
题意:刘汝佳训练指南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
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: