Uva 10817 Headmaster's Headache (DP+ 状态压缩)


Problem D: Headmaster‘s Headache


Time limit: 2 seconds

The headmaster of Spring Field School is considering employing some new teachers for certain subjects. There are a number of teachers applying for the posts. Each teacher is able to teach one or more subjects.
The headmaster wants to select applicants so that each subject is taught by at least two teachers, and the overall cost is minimized.

Input

The input consists of several test cases. The format of each of them is explained below:

The first line contains three positive integers SM andNS (≤ 8) is the number
of subjects, M (≤ 20) is the number of serving teachers, and N (≤ 100) is the number of applicants.

Each of the following M lines describes a serving teacher. It first gives the cost of employing him/her (10000 ≤ C ≤ 50000), followed by a list
of subjects that he/she can teach. The subjects are numbered from 1 to SYou must keep on employing all of them.After that there are N lines,
giving the details of the applicants in the same format.

Input is terminated by a null case where S = 0. This case should not be processed.

Output

For each test case, give the minimum cost to employ the teachers under the constraints.

Sample Input
2 2 2
10000 1
20000 2
30000 1 2
40000 1 2
0 0 0

Sample Output

60000

题意:有一个学校想要聘请老师,要求每个学科都有两个以上的老师授课,并且要使总

费用最小。有S(最多8个)个学科,现任的M(最多20个)个老师(你必须继续聘请他

们),N(最多100个)份申请。后来的M行每行有至少两个整数,表示现任的老师的工

资,和他所教授的课程(可能不止一个)。再后来的N行每行有也有至少两个整数表示

聘请这个老师所需的费用,以及他所教授的课程(可能不止一个)。

思路:因为要使每个学科都有两个以上的老师授课,所以不能用普通二进制表示。即可

以将每门学科的上课情况用二位二进制数表示。

即  将八位扩充为16位  具体细节看代码。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <climits>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
const int inf=INT_MAX;
const int M=110;
const int N=16;

vector <int> G[M];
int dp[M][1<<N],cost[M];
int s,n,m,num,sum,len;

void initial()
{
    len=1<<(2*s);
    for(int i=0;i<=n;i++)
        for(int j=0;j<len;j++)
             dp[i][j]=inf;
    for(int i=0;i<=n;i++)  G[i].clear();
    sum=num=0;
}

void input()
{
    string str;
    int x;
    getchar();
    for(int i=0;i<m;i++)
    {
         getline(cin,str);
         stringstream ss(str);
         ss>>x;
         sum+=x;
         while(ss>>x)
         {
              int one=2*x-2,two=2*x-1;
              if(num & 1<<one)  num |=(1<<two);
              else num |= (1<<one);
         }
    }
    for(int i=1;i<=n;i++)
    {
         getline(cin,str);
         stringstream ss(str);
         ss>>cost[i];
         while(ss>>x)  G[i].push_back(x);
    }
}

bool judge(int p,int q)
{
    for(int i=0;i<G[q].size();i++)
    {
         int one=2*G[q][i]-2,two=2*G[q][i]-1;
         if(!(p & 1<<one)  || !(p & 1<<two))  return  true;
    }
    return false;
}

void solve()
{
    dp[0][num]=sum;
    for(int i=1;i<=n;i++)
        for(int j=0;j<len;j++)
        {
             dp[i][j]=min(dp[i][j],dp[i-1][j]);
             if(dp[i-1][j]==inf)  continue;
             if(judge(j,i))
             {
                  int t=j;
                  for(int k=0;k<G[i].size();k++)
                  {
                       int one=2*G[i][k]-2,two=2*G[i][k]-1;
                       if(t & 1<<one)  t |=(1<<two);
                       else t |= (1<<one);
                  }
                  dp[i][t]=min(dp[i][t],dp[i-1][j]+cost[i]);
             }
        }
    printf("%d\n",dp[n][len-1]);
}

int main()
{
    while(scanf("%d %d %d",&s,&m,&n)!=EOF)
    {
         if(s==0)  break;
         initial();
         input();
         solve();
    }
    return 0;
}

Uva 10817 Headmaster's Headache (DP+ 状态压缩)

时间: 2024-10-23 19:07:31

Uva 10817 Headmaster's Headache (DP+ 状态压缩)的相关文章

UVA 10817 Headmaster&#39;s Headache 状压DP

记录两个状态S1,S2分别记录哪些课程被1个人教过或2个人教过,然后记忆化搜索 UVA - 10817 Headmaster's Headache Time Limit: 3000MS   Memory Limit: Unknown   64bit IO Format: %lld & %llu Submit Status Description Problem D: Headmaster's Headache Time limit: 2 seconds The headmaster of Spr

UVA - 10817 Headmaster&#39;s Headache (状压dp+记忆化搜索)

题意:有M个已聘教师,N个候选老师,S个科目,已知每个老师的雇佣费和可教科目,已聘老师必须雇佣,要求每个科目至少两个老师教的情况下,最少的雇佣费用. 分析: 1.为让雇佣费尽可能少,雇佣的老师应教他所能教的所有科目. 2.已聘老师必须选,候选老师可选可不选. 3.dfs(cur, subject1, subject2)---求出在当前已选cur个老师,有一个老师教的科目状态为 subject1,有两个及以上老师教的科目状态为 subject2的情况下,最少的雇佣费用. dp[cur][subje

状压DP UVA 10817 Headmaster&#39;s Headache

题目传送门 1 /* 2 题意:学校有在任的老师和应聘的老师,选择一些应聘老师,使得每门科目至少两个老师教,问最少花费多少 3 状压DP:一看到数据那么小,肯定是状压了.这个状态不好想,dp[s1][s2]表示s1二进制表示下至少有1位老师的科目集合 4 s2表示至少有2位老师的科目集合所花费的最小金额,状态转移方程(01):dp[t1][t2]=min(dp[t1][t2],dp[j][k]+c[i]); 5 j,k为当前两个集合,t1,t2为转移后的集合,另外求t1,t2用到了& |位运算

UVA - 10817 Headmaster&#39;s Headache (状压类背包dp+三进制编码)

题目链接 题目大意:有S门课程,N名在职教师和M名求职者,每名在职教师或求职者都有自己能教的课程集合以及工资,要求花费尽量少的钱选择一些人,使得每门课程都有至少两人教.在职教师必须选. 可以把“每个课程已经分别有几个人教”作为状态来进行转移,每个人能教的课程集合作为“物品重量”,工资作为“价值”来更新dp值,类似01背包,每放进一个人,从后往前更新即可. 状态的表示可以用三进制编码,为了写起来舒服,我写了个结构体作为状态和编码转换的桥梁,也可以进行状态的“加法运算”,虽然速度比较慢就是了~~ 有

(状压dp)uva 10817 Headmaster&#39;s Headache

题目地址 1 #include <bits/stdc++.h> 2 typedef long long ll; 3 using namespace std; 4 const int MAX=1e5+5; 5 const int INF=1e9; 6 int s,m,n; 7 int cost[125]; 8 //char sta[MAX]; 9 string sta; 10 int able[125]; 11 int dp[125][1<<8][1<<8]; 12 in

UVA 10817 - Headmaster&#39;s Headache

题目:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=20&page=show_problem&problem=1758 状态压缩的DP,dp[i][st]表示状态为st考虑后面i个人所有人最小花费, 因为每个科目有三种状态,可以用一个三进制数表示, 状态不是很多,所以可以把预先把每个数的三进制预处理出来, 决策为选和不选. #include<bits/std

【UVa】Headmaster&#39;s Headache(状压dp)

http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1758 晕....状压没考虑循环方向然后错了好久.. 这点要注意...(其实就是01背包变成了完全背包QAQ 我们将课程拆成两个点,然后状压 那么答案就是(1<<(s<<1))-1 转移就不说了,,,,,太简单.. #include <cstdio> #in

uva 11367 dijkstra+dp状态压缩

题意:给出n个地点 和 每个地点的油价 ,有 m 条边 , 并给出每条边长度 .1单位汽油可以走1千米  , 油箱的容量为 c , 在初始点 s 时 , 油箱中的油为 0 , 求s 到 t 的最小花费 . 解法: 定义 状态 d[i][j] 表示到达 地点 i 且油箱中有 j 单位油时的最小 花费. 对于状态的转移时 , 有两种方法: 1.把每个点的所有状态都求出 2.不把每个点的状态都求出 , 而是一单位一单位的加油. 对于第一种方法 , 会超时 , 因为每个点的状态太多 , 但是能用的状态就

uva 11825 ,Hacker&#39;s Crackdown 状态压缩 dp

// uva 11825 Hacker's Crackdown // // 题目意思看了很久才看懂,有n台计算机,有n种服务,每台计算机上运行所有 // 的服务,并且其中有的计算机与某些计算机相互邻接,对于每台计算机, // 你可以选择一项服务,停止这项服务,则与它邻接的计算机的该服务也停止了 // 你的目的是让经量多的服务完全瘫痪 // // 换而言之,这个问题就是在n个集合中(p[1]....p[n])分成尽量多的组数,使得每组 // 的并集等于全集(即所有的n台电脑都停止)... // /