• UVA


    题目大意:有一些老师,每一位都有自己的工资以及教授的课程。共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=='
    '||ch=='
    ') { 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=='
    '||ch=='
    ')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
    ",dp[All]);
    61       }
    62    return 0;
    63 }
  • 相关阅读:
    BZOJ5194: [Usaco2018 Feb]Snow Boots(排序&set)(可线段树优化)
    BZOJ5280: [Usaco2018 Open]Milking Order(二分+拓扑)
    BZOJ5281: [Usaco2018 Open]Talent Show(01分数规划&DP)
    BZOJ4837:[Lydsy1704月赛]LRU算法(双指针&模拟)
    【NOIP2013】传染病控制
    bzoj 2754: [SCOI2012]喵星球上的点名
    bzoj 4197: [Noi2015]寿司晚宴
    Codeforces Round #438 B. Race Against Time
    Codeforces Round #438 C. Qualification Rounds
    Codeforces Round #438 D. Huge Strings
  • 原文地址:https://www.cnblogs.com/D-O-Time/p/7717803.html
Copyright © 2020-2023  润新知