UVA - 10817 Headmaster's Headache

题目大意:有一些老师,每一位都有自己的工资以及教授的课程。共s<=8个课程。其中的一些老师必须选择,问你保证每节课至少有一个老师的最少总工资。

题解:

首先很容易想到状态压缩,搞一个3进制的数,分别表示每一门课程的情况,一共38=6561。但是这样是不行的,相当于暴力啊!
一个套路:三进制转化为二进制*2。也就是搞一个216的数,1~8和9~16表示每门课程,这样就可以利用位运算了。
然后知道这个就很显然的,一个背包问题。要注意,这样转化为二进制之后,要定义一条规则,每次添加课程,优先1~8位,有了就再加到9~16位即可。
处理出所有强制选择的老师的授课状态S,令dp[S]=sum{c[]}。其他的全是INF。然后从All=(1<<(s*2)-1到S。当成01背包做即可。

 1 #include<queue>
 2 #include<cstdio>
 3 #include<vector>
 4 #include<cstring>
 5 #include<iostream>
 6 #include<algorithm>
 7 #define RG register
 8 #define LL long long
 9 #define fre(a) freopen(a".in","r",stdin);//freopen(a".out","w",stdout);
10 using namespace std;
11 const int MAXN=1000;
12 int s,n,m,S,sum,All;
13 int c[MAXN],a[MAXN],dp[1<<16];
14 char ch;
15 int main()
16 {
17    while(scanf("%d%d%d",&s,&n,&m)!=EOF)
18       {
19          if(s==0)break;
20          All=(1<<(s*2))-1;
21          for(int i=1,flag,x;i<=n+m;i++)//鬼里鬼气的输入
22             {
23                a[i]=0;
24                scanf("%d",&c[i]);
25                flag=0;
26                while(1)
27                   {
28                      ch=getchar();
29                      while(ch<'0'||ch>'9')
30                         {
31                            if(ch=='\n'||ch=='\r') { flag=1; break; }
32                            ch=getchar();
33                         }
34                      if(flag)break;
35                      x=0;
36                      while('0'<=ch&&ch<='9')x=x*10+(ch-'0'),ch=getchar();
37                      a[i]|=(1<<(x-1));
38                      if(ch=='\n'||ch=='\r')break;
39                   }
40             }
41          S=sum=0;
42          for(int i=1;i<=n;i++)//按照规则,优先填后面的
43             {
44                sum+=c[i];
45                int p=S&a[i];
46                S|=(p<<s);
47                S|=a[i];
48             }
49          memset(dp,0x3f3f3f3f,sizeof dp);
50          dp[S]=sum;
51          for(int i=n+1;i<=n+m;i++)
52             {
53                for(int j=All;j>=S;j--)//按照规则,优先填后面的
54                   {
55                      int p=a[i]&j;
56                      p=a[i]|(p<<s);
57                      dp[j|p]=min(dp[j|p],dp[j]+c[i]);
58                   }
59             }
60          printf("%d\n",dp[All]);
61       }
62    return 0;
63 }
posted @ 2017-10-23 17:10  D_O_Time  阅读(297)  评论(0编辑  收藏  举报