【题】【DP(背包&状压)&输入略坑】NKOJ 3700 校长的烦恼

26 篇文章 0 订阅
5 篇文章 0 订阅

NKOJ 3700 校长的烦恼
时间限制 : - MS 空间限制 : 65536 KB
评测说明 : 时限1000ms

问题描述
某中学开设有s门课程,现有教师m个。今天有n个求职者来应聘新教师。
已知每个人工资和能教授的课程。
在职教师不能辞退,校长想知道,最少支付多少工资就能使得每门课都有至少两名教师能教。

输入格式
第一行,三个整数s,m和n
接下来m行,每行若干个整数,描述一名在职教师的情况:第一个整数,表示该教师的工资,接下来的若干整数表示该教师能教的课程;
接下来n行,每行若干个整数,描述一名求职者的情况:第一个整数,表示该求职者要求的工资,接下来的若干整数表示该求职者能教的课程;
注意,每行末尾有空格

输出格式
一行,一个整数,表示所求结果。
若无解,输出-1

样例输入 1
2 2 2
10000 1
20000 2
30000 1 2
40000 1 2

样例输出 1
60000

样例输入 2
5 2 4
24 2 4
39 4 1
9 4
81 2 1 5
19 2 3 5
65 3 1

样例输出 2
228

提示
1<=s<=8
1<=m<=20
1<=n<=100
1<=每个人的工资<=50000
1<=每个人教的课的编号<=s

来源 改编自uva 10817

状态:f[s2][s1]表示至少有一名教师教的课程为s1,至少两名教师教的课程为s2,时取得的最小代价
决策:每名应聘教师选或者不选
方程:f[s2][s1]=min(f[i][j]+cost[k])

#include<cstdio> 
#include<iostream> 
using namespace std; 
const int inf=1e9; 
const int need=(1<<8)+4; 

int ab[103],cost[103],f[need][need]; 
int a,n,m; 
char *p; 

void get(int &c) 
{ 
    for(c=0;*p>='0'&&*p<='9';p++) c=c*10+*p-'0'; 
}  

int main() 
{ 
    scanf("%d%d%d",&a,&m,&n); 
    char b[1000]; 
    int cnt=0,temp,mn=m+n,s1=0,s2=0,c; 
    int s=(1<<a)-1; 
    gets(b); 
    for(int i=1;i<=mn;i++) 
    { 
        gets(b); 
        p=b; 
        get(c); 
        if(i<=m) cnt+=c; 
        else cost[i-m]=c; 
        while(*p==' '&&*(p+1)>='0'&&*(p+1)<='9')  
        { 
            p++; 
            get(c); 
            c--; 
            if(i<=m) 
            { 
                if(s1&(1<<c)) s2|=(1<<c); 
                else s1|=(1<<c); 
            } 
            else ab[i-m]|=1<<c; 
        } 
    } 
    for(int j,i=0;i<=s;i++) 
     for(j=0;j<=s;j++) 
      f[i][j]=inf; 
    f[s2][s1]=cnt; 
    for(int i,j,k=1;k<=n;k++) 
     for(i=s;i>=0;i--) 
      for(j=s;j>=0;j--) 
      { 
          if(f[i][j]>=inf) continue; 
          s2=i|(j&ab[k]); 
          s1=j|ab[k]; 
          f[s2][s1]=min(f[s2][s1],f[i][j]+cost[k]); 
      } 
    printf("%d",f[s][s]); 
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值